when /_this/ has program code /programCode/ \n\ \ \ \ if\ \{\$_this\ eq\ \"builtin-programs/collect.f (
[ m1:0 (s6:0) ]
[ m2:0 (s5:0) ]
[ m3:0 (s7:0) ]
[ m4:0 (s20:0) ]
[ m5:0 (s11:0) ]
[ m6:0 (s13:0) ]
[ m7:0 (s17:0) ]
[ m8:0 (s22:0) ]
[ m9:0 (s23:0) ]
[ m10:0 (s19:0) ]
[ m11:0 (s21:0) ]
[ m12:0 (s29:0) ]
[ m13:0 (s27:0) ]
[ m14:0 (s28:0) ]
[ m15:0 (s34:0) ]
[ m16:0 (s32:0) ]
[ m17:0 (s35:0) ]
[ m18:0 (s37:0) ]
[ m20:0 (s44:0) ]
[ m21:0 (s41:0) ]
[ m22:0 (s43:0) ]
[ m23:0 (s46:0) ]
[ m29:0 (s54:0) ]
[ m33:0 (s67:0) ]
[ m47:0 (s77:0) ]
[ m50:0 (s82:0) ]
[ m52:0 (s81:0) ]
[ m53:0 (s84:0) ]
[ m57:0 (s89:0) ]
[ m58:0 (s91:0) ]
[ m60:0 (s95:0) ]
[ m62:0 (s98:0) ]
[ m64:0 (s101:0) ]
[ m66:0 (s104:0) ]
[ m68:0 (s106:0) ]
[ m71:0 (s114:0) ]
[ m72:0 (s111:0) ]
[ m73:0 (s113:0) ]
[ m76:0 (s119:0) ]
[ m78:0 (s122:0) ]
[ m80:0 (s124:0) ]
[ m83:0 (s127:0) ]
[ m85:0 (s136:0) ]
[ m86:0 (s132:0) ]
[ m87:0 (s133:0) ]
[ m90:0 (s143:0) ]
[ m92:0 (s141:0) ]
[ m93:0 (s145:0) ]
[ m95:0 (s147:0) ]
[ m99:0 (s151:0) ]
[ m101:0 (s154:0) ]
[ m103:0 (s158:0) ]
[ m104:0 (s162:0) ]
[ m106:0 (s161:0) ]
[ m109:0 (s168:0) ]
[ m110:0 (s167:0) ]
[ m112:0 (s172:0) ]
[ m115:0 (s180:0) ]
[ m116:0 (s177:0) ]
[ m117:0 (s181:0) ]
[ m119:0 (s183:0) ]
[ m123:0 (s188:0) ]
[ m124:0 (s190:0) ]
[ m126:0 (s192:0) ]
[ m129:0 (s197:0) ]
[ m130:0 (s198:0) ]
[ m133:0 (s202:0) ]
[ m135:0 (s208:0) ]
[ m136:0 (s206:0) ]
[ m139:0 (s216:0) ]
[ m140:0 (s213:0) ]
[ m141:0 (s215:0) ]
[ m145:0 (s226:0) ]
[ m146:0 (s222:0) ]
[ m147:0 (s223:0) ]
[ m151:0 (s229:0) ]
[ m153:0 (s234:0) ]
[ m154:0 (s233:0) ]
[ m157:0 (s239:0) ]
[ m158:0 (s244:0) ]
[ m159:0 (s243:0) ]
[ m161:0 (s246:0) ]
[ m163:0 (s250:0) ]
[ m167:0 (s254:0) ]
[ m168:0 (s256:0) ]
[ m171:0 (s260:0) ]
[ m172:0 (s261:0) ]
[ m175:0 (s266:0) ]
[ m176:0 (s267:0) ]
[ m179:0 (s271:0) ]
[ m181:0 (s275:0) ]
[ m182:0 (s277:0) ]
[ m183:0 (s281:0) ]
[ m186:0 (s282:0) ]
[ m189:0 (s288:0) ]
[ m190:0 (s287:0) ]
[ m192:0 (s293:0) ]
[ m194:0 (s296:0) ]
[ m196:0 (s299:0) ]
[ m198:0 (s301:0) ]
[ m201:0 (s305:0) ]
[ m202:0 (s307:0) ]
[ m205:0 (s312:0) ]
[ m206:0 (s311:0) ]
[ m47946:638 (s15550:765) ]
[ m33928:727 (s14336:866) ]
[ m6504:986 (s53020:1175) ]
[ m6717:990 (s53276:1175) ]
[ m3370:1022 (s32221:1214) ]
[ m59642:1050 () ]
[ m33967:1051 () ]
[ m42630:1051 () ]
[ m1756:1055 () ]
[ m43480:1050 () ]
[ m24862:1056 () ]
[ m65091:1057 () ]
[ m47707:1063 (s64458:1262) ]
)when /_this/ has program code /programCode/ \n\ \ \ \ if\ \{\$_this\ eq\ \"builtin-programs/collect.folk\"\}\ \{\n\ \ \ \ \ \ \ \ #\ We\ don't\ have\ Collect\ available\ in\ boot.folk\ yet,\ since\ it's\n\ \ \ \ \ \ \ \ #\ implemented\ in\ userspace,\ so\ we\ can't\ do\ the\ queries.\ Just\n\ \ \ \ \ \ \ \ #\ run\ it\ always.\n\ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ does\ not\ run\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {}
when the collected results for {/any/ wishes program builtin-programs/group.folk does not run} are /_ (
[ m24:0 (s55:0) ]
[ m227:0 (s344:0 s353:0) ]
)when the collected results for {/any/ wishes program builtin-programs/group.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/group.folk programCode return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contains\ /...programs/\ \{\n\ \ \ \ Wish\ tag\ \$group\ is\ stabilized\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ claim\ 'tag'\ specifically\ so\ it\ doesn't\ run\ twice\n\ \ \ \ \ \ \ \ Claim\ tag\ \$program\ has\ a\ program\n\ \ \ \ \}\n\}\n\n#\ figure\ out\ the\ text\ to\ display\ below\nWhen\ group\ /group/\ contains\ /...programs/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ /program/\ is\ titled\ /title/\]\ are\ /results/\ \{\n\ \ \ \ set\ programTitles\ \[dict\ create\]\n\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ programId\ \[dict\ get\ \$result\ program\]\n\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$programs\ \$programId\]\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ programTitles\ \$programId\ \[dict\ get\ \$result\ title\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ programTitleText\ \"\"\n\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ set\ title\ \[dict_getdef\ \$programTitles\ \$program\ \"(no\ title)\"\]\n\ \ \ \ \ \ \ \ append\ programTitleText\ \\n\ \$program\ \":\ \"\ \$title\n\ \ \ \ \}\n\n\ \ \ \ Claim\ group\ \$group\ has\ program\ titles\ \$programTitleText\n\}\n\n#\ display\ said\ text\nWhen\ group\ /group/\ has\ program\ titles\ /programTitles/\ &\\\n\ \ \ \ \ /group/\ has\ region\ /r/\ \{\n\ \ \ \ set\ radians\ \[region\ angle\ \$r\]\n\ \ \ \ set\ pos\ \[region\ topleft\ \[region\ move\ \$r\ down\ 40px\ right\ 15px\]\]\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ text\ \$programTitles\ scale\ 0.7\ radians\ \$radians\ anchor\ topleft\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/points-at.folk does not run} ar (
[ m25:0 (s51:0) ]
[ m229:0 (s360:0 s371:0) ]
)when the collected results for {/any/ wishes program builtin-programs/points-at.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/points-at.folk programCode When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ \$l\n\}\n\nWhen\ when\ /rect/\ points\ /direction/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ 1\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /rect/\ points\ /direction/\ with\ length\ /l/\ \{\n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/music.folk does not run} are /_ (
[ m27:0 (s52:0) ]
[ m225:0 (s351:0 s363:0) ]
)when the collected results for {/any/ wishes program builtin-programs/music.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/music.folk programCode {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set musicDir $::env(HOME)/music
exec mkdir -p $musicDir
# https://raw.githubusercontent.com/tidalcycles/Tidal/main/BootTidal.hs
set bootTidal {
:set -XOverloadedStrings
:set prompt ""
import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)
hSetEncoding stdout utf8
tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})
:{
let only = (hush >>)
p = streamReplace tidal
hush = streamHush tidal
panic = do hush
once $ sound "superpanic"
list = streamList tidal
mute = streamMute tidal
unmute = streamUnmute tidal
unmuteAll = streamUnmuteAll tidal
unsoloAll = streamUnsoloAll tidal
solo = streamSolo tidal
unsolo = streamUnsolo tidal
once = streamOnce tidal
first = streamFirst tidal
asap = once
nudgeAll = streamNudgeAll tidal
all = streamAll tidal
resetCycles = streamResetCycles tidal
setCycle = streamSetCycle tidal
setcps = asap . cps
getcps = streamGetcps tidal
getnow = streamGetnow tidal
xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
jump i = transition tidal True (Sound.Tidal.Transition.jump) i
jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
d13 = p 13
d14 = p 14
d15 = p 15
d16 = p 16
:}
:{
let getState = streamGet tidal
setI = streamSetI tidal
setF = streamSetF tidal
setS = streamSetS tidal
setR = streamSetR tidal
setB = streamSetB tidal
:}
:set prompt "tidal> "
:set prompt-cont ""
default (Pattern String, Integer, Double)
}
set scStartup [open $musicDir/startup.sc w]
# via https://club.tidalcycles.org/t/tidal-synth-doesnt-work/800 -- it
# doesn't work if you just do SuperDirt.start; for some reason
puts $scStartup {(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 2048; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt.stop; // stop any old ones, avoid duplicate dirt (if it is nil, this won't do anything)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
SuperDirt.default = ~dirt; // make this instance available in sclang (optional)
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
// directly below here, in your own copy of this file, you could add further code that you want to call on startup
// this makes sure the server and ~dirt are running
// you can keep this separate and make it easier to switch between setups
// by using "path/to/my/file.scd".load and if necessary commenting out different load statements
// ...
};
s.latency = 0.3; // increase this if you get "late" messages
};
);}
close $scStartup
set uid [exec id -u $::env(USER)]
set ::env(DBUS_SESSION_BUS_ADDRESS) "unix:path=/run/user/$uid/bus"
exec rm -f $musicDir/music.log
fn musicExec {args} {
if {[lindex $args end] eq "&"} {
exec {*}[lreplace $args end end] >>$musicDir/music.log 2>>$musicDir/music.log &
} else {
exec {*}$args >>$musicDir/music.log 2>>$musicDir/music.log
}
}
fn musicFinishSetup {} {
if {$::thisNode eq "folk-hex"} {
exec jackd -d alsa -d hdmi:CARD=NVidia -r 48000 -p 1024 -n 2 &
} elseif {$::thisNode eq "folk-sva"} {
exec jackd -d alsa -d hdmi:CARD=Generic,DEV=1 -r 48000 -p 1024 -n 2 &
}
catch {exec pkill ghci}
catch {exec pkill ghc}
catch {exec pkill sclang}
catch {exec pkill scsynth}
sleep 0.4
set ::env(QT_QPA_PLATFORM) offscreen
musicExec sclang $musicDir/startup.sc &
set fifo $musicDir/tidal-input
exec rm -f $fifo
exec mkfifo $fifo
sleep 0.2
musicExec sh -c "ghci < $fifo" &
set fifoId [open $fifo w]
puts $fifoId $bootTidal; flush $fifoId
# We keep $fifoId open so that ghci doesn't get an EOF.
}
while true {
puts "music: Waiting for D-Bus."
sleep 0.2
if {[file exists /run/user/$uid/bus]} {
puts "music: Found D-Bus."
musicFinishSetup
break
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/laser.folk does not run} are /_ (
[ m26:0 (s50:0) ]
[ m228:0 (s350:0 s361:0) ]
)when the collected results for {/any/ wishes program builtin-programs/laser.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/laser.folk programCode When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/mask-tags.folk does not run} ar (
[ m28:0 (s53:0) ]
[ m224:0 (s341:0 s346:0) ]
)when the collected results for {/any/ wishes program builtin-programs/mask-tags.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/mask-tags.folk programCode When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ width\ /projWidth/\ height\ /projHeight/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ intrinsics\ /projectorIntrinsics/\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/programs.folk does not run} are (
[ m30:0 (s57:0) ]
[ m230:0 (s359:0 s366:0) ]
)when the collected results for {/any/ wishes program builtin-programs/programs.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/programs.folk programCode When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{\$tag\ >=\ 48600\}\ \{\ return\ \}\n\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ has\ a\ program\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ is\ a\ tag\n\}\n\nWhen\ -noncapturing\ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n} {}}
when the collected results for {/any/ wishes program builtin-programs/errors.folk does not run} are / (
[ m32:0 (s58:0) ]
[ m223:0 (s342:0 s348:0) ]
)when the collected results for {/any/ wishes program builtin-programs/errors.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/errors.folk programCode {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
}
When /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk does not run (
[ m34:0 (s62:0) ]
[ m280:0 (s476:0 s496:0) ]
)when the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/tags-to-quads.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/terminal.folk does not run} are (
[ m36:0 (s59:0) ]
[ m221:0 (s340:0 s347:0) ]
)when the collected results for {/any/ wishes program builtin-programs/terminal.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/terminal.folk programCode #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/demos.folk does not run} are /_ (
[ m37:0 (s60:0) ]
[ m226:0 (s343:0 s349:0) ]
)when the collected results for {/any/ wishes program builtin-programs/demos.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/demos.folk programCode {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
Claim 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
Claim 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
Claim 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
Claim 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
Claim 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
Claim 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
Claim 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
Claim 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/apriltags.folk does not run} ar (
[ m38:0 (s64:0) ]
[ m285:0 (s457:0 s464:0) ]
)when the collected results for {/any/ wishes program builtin-programs/apriltags.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/apriltags.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/intersect.folk does not run} ar (
[ m39:0 (s61:0) ]
[ m275:0 (s418:0 s423:0) ]
)when the collected results for {/any/ wishes program builtin-programs/intersect.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/intersect.folk programCode \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ /r2/\ \{\n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n\}\n\nWhen\ when\ /p/\ has\ neighbor\ /n/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ Wish\ \$p\ has\ neighbors\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/regions.folk does not run} are (
[ m40:0 (s65:0) ]
[ m289:0 (s448:0 s450:0) ]
)when the collected results for {/any/ wishes program builtin-programs/regions.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/regions.folk programCode {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1/ has region /r1/ & /p2/ has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}
When /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/shapes.folk does not run} are / (
[ m41:0 (s68:0) ]
[ m293:0 (s469:0 s488:0) ]
)when the collected results for {/any/ wishes program builtin-programs/shapes.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/shapes.folk programCode set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octagon\ 8\ nonagon\ 9\]\n\nproc\ process_offset\ \{offset\ region\}\ \{\n\ \ if\ \{!\[info\ exists\ region\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ set\ w\ \[region\ width\ \$region\]\n\ \ set\ h\ \[region\ height\ \$region\]\n\ \ \n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \n\ \ \ \ \ \ !\[string\ match\ *%*\ \$offset\]\ &&\ \n\ \ \ \ \ \ !\[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ simple\ percentage\ string:\ \"50%\"\n\ \ if\ \{\[string\ match\ *%*\ \$offset\]\ &&\ \[llength\ \$offset\]\ ==\ 1\}\ \{\n\ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$offset\]\ /\ 100.0\}\]\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \ #\ Default\ to\ horizontal\ offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ strings:\ \"right\",\ \"left\",\ \"up\",\ \"down\"\n\ \ if\ \{\$offset\ eq\ \"right\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"left\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{-\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"up\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ 0.5\}\]\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"down\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{\$h\ *\ 0.5\}\]\]\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ percentage:\ \"right\ 50%\",\ \"left\ 25%\",\ etc.\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ set\ direction\ \[lindex\ \$offset\ 0\]\n\ \ \ \ set\ amount\ \[lindex\ \$offset\ 1\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$amount\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$amount\]\ /\ 100.0\}\]\n\n\ \ \ \ \ \ switch\ \$direction\ \{\n\ \ \ \ \ \ \ \ \"right\"\ \{\ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"left\"\ \ \{\ return\ \[list\ \[expr\ \{-\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"up\"\ \ \ \ \{\ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ \"down\"\ \ \{\ return\ \[list\ 0\ \[expr\ \{\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ default\ \{\ return\ \[list\ 0\ 0\]\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\ \ \n\ \ #\ Handle\ x\ y\ vector\ where\ one\ or\ both\ components\ have\ percentage\ notation\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\}\ \{\n\ \ \ \ lassign\ \$offset\ ox\ oy\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$ox\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$ox\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ ox\ \[expr\ \{\$w\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$oy\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$oy\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ oy\ \[expr\ \{\$h\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ \[list\ \$ox\ \$oy\]\n\ \ \}\n\ \ \n\ \ #\ Default\ fallback\n\ \ return\ \$offset\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ shape\ with\ /...options/\ \{\n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ color\ white\n\}\n\n#\ Handle\ \"a\"\ vs\ \"an\"\ grammar\ variations\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n\}\ \n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ \{\n\ \ \ \ Wish\ \$p\ draws\ text\ \$text\ with\ color\ white\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\n#\ Pass\ through\ options\ for\ \"an\"\ version\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ with\ /...options/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ \{*\}\$options\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ rect\ with\ width\ /w/\ height\ /h/\ \{\n\ \ Wish\ \$p\ draws\ a\ rect\ with\ width\ \$w\ height\ \$h\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ radius\ /rad/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ radius\ \$rad\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ set\ of\ points\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ polyline\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ Center\ circle\n\ \ Wish\ \$this\ draws\ a\ circle\n\ \ \n\ \ #\ Grid\ of\ shapes\ with\ varying\ thickness\n\ \ set\ baseX\ -850\n\ \ set\ baseY\ -200\n\ \ set\ gridSpacing\ 130\n\n\ \ #\ Row\ 0:\ Title\n\ \ Wish\ \$this\ draws\ text\ \"triangle\"\ with\ color\ skyblue\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"square\"\ with\ color\ green\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"pentagon\"\ with\ color\ gold\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"hexagon\"\ with\ color\ orange\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ \n\ \ #\ Row\ 1:\ Regular\ polygons\ with\ different\ colors\ and\ thickness\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ thickness\ 2\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ thickness\ 4\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ thickness\ 6\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ thickness\ 8\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ \n\ \ #\ Row\ 2:\ Filled\ shapes\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ filled\ true\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\n\ \ #\ Row\ 3:\ Directional\ offset\ examples\ (replacing\ shift)\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ radius\ 40\ offset\ \"right\ 50%\"\ color\ skyblue\n\ \ Wish\ \$this\ draws\ a\ square\ with\ radius\ 40\ offset\ \ \"left\ 50%\"\ color\ green\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ radius\ 40\ offset\ \"up\ 50%\"\ color\ gold\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ radius\ 40\ offset\ \"down\ 50%\"\ color\ orange\n\ \ \n\ \ #\ Row\ 4:\ Rectangles\ with\ different\ properties\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ cyan\ thickness\ 3\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ magenta\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \"right\ 50%\"\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \ \"left\ 50%\"\n\ \ \n#\ Animated\ elements\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ angle\ \$r\]\ angle\n\ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 8\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ offsetVector\ \[list\ \[sin\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\ \[*\ 2\ \[cos\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\]\]\n\ \ \ \ \ \ \ \ \ \ set\ vector\ \[::vec2::scale\ \$offsetVector\ \[+\ \[*\ \$i\ \$i\]\ 15\]\]\n\ \ \ \ \ \ \ \ \ \ Wish\ \$this\ draws\ a\ circle\ with\ radius\ \$i\ color\ palegoldenrod\ offset\ \$vector\n\ \ \ \ \ \ \}\n\ \ \}\n\ \ \n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(sin(\$t)\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[-\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[-\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fillVal\"\ color\ red\n\ \ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(\$t\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[+\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[+\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fill\"\ color\ red\n\ \ \}\n\ \ \n\ \ Wish\ \$this\ is\ outlined\ white\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/sprites.folk does not run} are (
[ m42:0 (s69:0) ]
[ m297:0 (s462:0 s468:0) ]
)when the collected results for {/any/ wishes program builtin-programs/sprites.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/sprites.folk programCode ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumbnail\ grid\ with\ 8\ frames\ and\ 4\ columns\n#\ \ \ When\ \$this\ has\ thumbnail\ grid\ /thumbnails/\ \{\n#\ \ \ \ \ Wish\ \$this\ draws\ \$thumbnails\;\ #\ Would\ need\ to\ query\ \$thumnails\ for\ its\ frameCount\ and\ columns\n#\ \ \ \}\n#######\n\n#\ -\ path\ get\ prepended\ with\ ~/folk-images/\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /anyone/\ wishes\ /p/\ draws\ sprite\ /path/\ with\ /...options/\ \{\n\n\ \ set\ frames\ \[dict\ get\ \$options\ frames\]\n\ \ set\ columns\ \[dict\ get\ \$options\ columns\]\n\ \ set\ fps\ \[dict\ getdef\ \$options\ fps\ 60\]\n\n\ \ fn\ loadImage\n\ \ set\ im\ \[loadImage\ \$path\]\n\n\ \ set\ sheetWidth\ \[\$imageLib\ Image_width\ \$im\]\n\ \ set\ sheetHeight\ \[\$imageLib\ Image_height\ \$im\]\n\ \ set\ spriteWidth\ \[/\ \$sheetWidth\ \$columns\]\n\ \ set\ rows\ \[/\ \$frames\ \$columns\]\n\ \ set\ spriteHeight\ \[/\ \$sheetHeight\ \$rows\]\n\n\ \ When\ -atomicallyWithKey\ \[list\ sprite\ \$p\ \$path\]\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ set\ frameNumber\ \[expr\ \{round\ (\$t\ *\ \$fps)\ %\ \$frames\}\]\n\ \ \ \ \ \ set\ x\ \[expr\ \{(\$frameNumber\ %\ \$columns)\ *\ \$spriteWidth\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{(\$frameNumber\ %\ \$rows)\ *\ \$spriteHeight\}\]\n\n\ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$im\ \$x\ \$y\ \$spriteWidth\ \$spriteHeight\]\n\ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$subimage\ with\ \{*\}\$options\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ Wish\ \$this\ draws\ sprite\ \$path\ with\ 8\ frames\ and\ 4\ columns\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/audio.folk does not run} are /_ (
[ m43:0 (s72:0) ]
[ m311:0 (s501:0 s514:0) ]
)when the collected results for {/any/ wishes program builtin-programs/audio.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/audio.folk programCode #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n#\ ALSA,\ PulseAudio,\ or\ JACK\ drivers.\n#\n#\ See\ https://miniaud.io/.\ We\ are\ using\ Miniaudio\ v0.11.23.\n#\n#\ Examples:\n#\n#\ Play\ a\ sound\ file\ in\ assets/sounds/\ or\ user-programs/\$hostname/sounds:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ drums.wav\n#\n#\ Play\ a\ sound\ file\ by\ absolute\ path:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ /home/folk/sounds/drums.wav\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/miniaudio\n\nif\ \{!\[catch\ \{exec\ which\ sclang\}\]\}\ \{\n\ \ \ \ #\ HACK:\ We're\ running\ msuic.folk\ and\ therefore\ are\ running\ JACK,\n\ \ \ \ #\ so\ we\ should\ force\ miniaudio\ to\ not\ use\ ALSA\ directly\ (because\n\ \ \ \ #\ that\ won't\ work).\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ MA_NO_ALSA\n\ \ \ \ \ \ \ \ #define\ MA_NO_PULSEAUDIO\n\ \ \ \ \}\n\}\n\$cc\ code\ \{\n\ \ \ #define\ MINIAUDIO_IMPLEMENTATION\n\}\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <stdint.h>\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <miniaudio.h>\n\nif\ \{\$::tcl_platform(os)\ ne\ \"Darwin\"\}\ \{\n\ \ \ \ \$cc\ endcflags\ -lpthread\ -lm\ -ldl\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ ma_context\ \ \ \ \ g_ctx\;\n\ \ \ \ static\ ma_engine\ \ \ \ \ \ g_engine\;\n\ \ \ \ static\ ma_sound_group\ g_group\;\n\n\ \ \ \ static\ bool\ g_ctx_initialized\ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_engine_initialized\ =\ false\;\n\ \ \ \ static\ bool\ g_engine_started\ \ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_group_initialized\ \ =\ false\;\n\n\ \ \ \ static\ pthread_mutex_t\ g_state_mtx\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ typedef\ struct\ SoundNode\ \{\n\ \ \ \ \ \ \ \ ma_sound*\ \ \ \ \ \ \ \ \ snd\;\n\ \ \ \ \ \ \ \ struct\ SoundNode*\ next\;\n\ \ \ \ \}\ SoundNode\;\n\n\ \ \ \ static\ SoundNode*\ \ \ \ \ \ g_head\ \ \ \ \ \ \ \ \ \ \ \ =\ NULL\;\n\ \ \ \ static\ pthread_mutex_t\ g_list_mtx\ \ \ \ \ \ \ \ =\ PTHREAD_MUTEX_INITIALIZER\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ \ =\ false\;\n\ \ \ \ static\ pthread_t\ \ \ \ \ \ \ g_reaper_thr\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ /*\ Maintains\ linked\ list\ of\ active\ sounds\ */\n\ \ \ \ static\ bool\ registry_add(ma_sound*\ snd)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ (SoundNode*)malloc(sizeof\ *node)\;\n\n\ \ \ \ \ \ \ \ if\ (!node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ registry_add:\ alloc\ failed\\n\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ node->snd\ =\ snd\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ node->next\ =\ g_head\;\n\ \ \ \ \ \ \ \ g_head\ =\ node\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Removes\ and\ uninitializes\ all\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void\ registry_clear_locked(void)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ next\ =\ node->next\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (node->snd)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(node)\;\n\ \ \ \ \ \ \ \ \ \ \ \ node\ =\ next\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ g_head\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Background\ thread\ that\ periodically\ removes\ finished\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void*\ reaper_main(void*\ arg)\ \{\n\ \ \ \ \ \ \ \ (void)arg\;\n\n\ \ \ \ \ \ \ \ while\ (!g_shutdown_reaper)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ \ node\ \ =\ g_head\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound*\ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ remove\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (snd\ &&\ !ma_sound_is_playing(snd)\ &&\ !ma_sound_is_looping(snd))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Collect\ finished\ sounds\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remove\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (remove)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(to_free)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ usleep(50\ *\ 1000)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ registry_clear_locked()\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ g_reaper_running\ =\ false\;\n\ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ static\ int\ reaper_start(void)\ \{\n\ \ \ \ \ \ \ \ if\ (g_reaper_running)\ return\ 0\;\n\ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ \ \ \ \ int\ err\ =\ pthread_create(&g_reaper_thr,\ NULL,\ reaper_main,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (err\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ err\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Initializes\ the\ audio\ backend\ and\ sound\ group,\ and\ starts\ the\ reaper\ thread\ */\n\ \ \ \ static\ bool\ audio_init_impl(void)\ \{\n\ \ \ \ \ \ \ \ ma_result\ r\;\n\n\ \ \ \ \ \ \ \ if\ (!g_ctx_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_context_init(NULL,\ 0,\ NULL,\ &g_ctx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ context\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_ctx_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ma_engine_config\ cfg\ =\ ma_engine_config_init()\;\n\ \ \ \ \ \ \ \ \ \ \ \ cfg.pContext\ =\ &g_ctx\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_init(&cfg,\ &g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"miniaudio:\ engine\ initialized\ with\ %s\ backend\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_get_backend_name(g_ctx.backend))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_started)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_start(&g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ start\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_group_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_sound_group_init(&g_engine,\ 0,\ NULL,\ &g_group)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ group\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Unwind\ engine\ on\ group\ failure\;\ context\ remains\ for\ future\ attempts\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_engine_uninit(&g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memset(&g_engine,\ 0,\ sizeof\ g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_group_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ err\ =\ reaper_start()\;\n\n\ \ \ \ \ \ \ \ if\ (err\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"audio:\ reaper\ thread\ create\ failed:\ %d\\n\",\ err)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ audioInit\ \{\}\ bool\ \{\n\ \ \ \ pthread_mutex_lock(&g_state_mtx)\;\n\ \ \ \ bool\ success\ =\ audio_init_impl()\;\n\ \ \ \ pthread_mutex_unlock(&g_state_mtx)\;\n\n\ \ \ \ if\ (success)\ \{\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ERROR(\"miniaudio:\ audio\ init\ failed\\n\")\;\n\ \ \ \ return\ false\;\n\}\n\n\$cc\ proc\ audioStop\ \{ma_sound*\ target\}\ void\ \{\n\ \ \ \ SoundNode*\ to_free\ =\ NULL\;\n\ \ \ \ ma_sound*\ snd\ =\ NULL\;\n\n\ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ /*\ Find\ the\ sound\ to\ stop.\ TODO:\ this\ duplicates\ traversal\ logic\ from\ the\ reaper\ thread\ */\n\ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ if\ (node->snd\ ==\ target)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ node->snd\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ /*\ Sound\ already\ reaped\ or\ never\ registered\ */\n\ \ \ \ if\ (!to_free)\ return\;\n\n\ \ \ \ if\ (snd)\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ snd\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ free(to_free)\;\n\}\n\n\$cc\ proc\ playSound\ \{char*\ path\}\ ma_sound*\ \{\n\ \ \ \ ma_sound*\ snd\ =\ (ma_sound*)malloc(sizeof\ *snd)\;\n\n\ \ \ \ if\ (!snd)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ alloc\ sound\ failed\\n\")\;\n\ \ \ \ \}\n\n\ \ \ \ ma_result\ r\ =\ ma_sound_init_from_file(&g_engine,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MA_SOUND_FLAG_DECODE\ |\ MA_SOUND_FLAG_NO_SPATIALIZATION,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &g_group,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ init\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ r\ =\ ma_sound_start(snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ start\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (!registry_add(snd))\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ registry\ add\ failed\ for\ %s\\n\",\ path)\;\n\ \ \ \ \}\n\n\ \ \ \ fprintf(stderr,\ \"miniaudio:\ playing\ %s\\n\",\ path)\;\n\ \ \ \ return\ snd\;\n\}\n\ntry\ \{\n\ \ \ \ set\ audioLib\ \[\$cc\ compile\]\n\ \ \ \ set\ success\ \[\$audioLib\ audioInit\]\n\n\ \ \ \ if\ \{!\$success\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ init\ failed\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ audio\ library\ is\ \$audioLib\n\}\ on\ error\ e\ \{\n\ \ \ \ puts\ stderr\ \"audio:\ compile\ failed:\ \$e\"\n\}\n\nWhen\ the\ audio\ library\ is\ /audioLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ play\ audio\ /sound/\ \{\n\n\ \ \ \ #\ Check\ if\ the\ sound\ file\ exists\ in\ the\ user-programs/\$hostname/sounds\ directory\n\ \ \ \ #\ or\ in\ the\ working\ directory's\ assets/sounds\ subdirectory.\ Otherwise,\ assume\n\ \ \ \ #\ it's\ an\ absolute\ path.\n\ \ \ \ proc\ resolveSoundPath\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ scriptDir\ \[file\ dirname\ \[info\ script\]\]\n\ \ \ \ \ \ \ \ set\ projectRoot\ \[pwd\]\n\ \ \ \ \ \ \ \ set\ hostname\ \[info\ hostname\]\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/user-programs/\$hostname/audio/\$filename\"\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/audio/\$filename\"\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ #\ treat\ as\ an\ absolute\ path\n\ \ \ \ \ \ \ \ return\ \$filename\n\ \ \ \ \}\n\n\ \ \ \ set\ path\ \[resolveSoundPath\ \$sound\]\n\n\ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ File\ not\ found\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ handle\ \[\$audioLib\ playSound\ \$path\]\n\n\ \ \ \ if\ \{\$handle\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ Failed\ to\ play\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ puts\ \"audio:\ stopping\ audio\ '\$path'\"\n\ \ \ \ \ \ \ \ \$audioLib\ audioStop\ \$handle\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/keyboard.folk does not run} are (
[ m44:0 (s70:0) ]
[ m299:0 (s475:0 s482:0) ]
)when the collected results for {/any/ wishes program builtin-programs/keyboard.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/keyboard.folk programCode #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ \ \ set\ properties\ \[exec\ udevadm\ info\ --query=property\ --name=\$device\]\n\ \ \ \ if\ \{\$properties\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ false\n\ \ \ \ \}\n\ \ \ \ set\ isKeyboard\ \[string\ match\ *ID_INPUT_KEYBOARD=1*\ \$properties\]\n\ \ \ \ return\ \$isKeyboard\n\ \ \ \ #\ TODO:\ Excluding\ mice\ would\ nice\ to\ keey\ the\ list\ of\ keyboard\ devices\ short\n\ \ \ \ #\ \ \ \ \ \ \ Alas,\ including\ mice\ is\ necessary\ for\ the\ Logitech\ K400R\ keyboard\n\ \ \ \ #\ set\ isMouse\ \[string\ match\ *ID_INPUT_MOUSE=1*\ \$properties\]\n\ \ \ \ #\ return\ \[expr\ \{\$isKeyboard\ &&\ !\$isMouse\}\]\n\}\n\n####\n#\ /dev/input/event*\ addresses\ are\ the\ ground\ truth\ for\ keyboard\ devices\n#\n#\ This\ function\ goes\ through\ each\ of\ them\ and\ checks\ if\ they\ are\ keyboards\nproc\ walkInputEventPaths\ \{\}\ \{\n\ \ \ \ #\ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/event*\"\]\n\ \ \ \ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/by-path/*\"\]\n\ \ \ \ set\ keyboards\ \[list\]\n\ \ \ \ foreach\ device\ \$allDevices\ \{\n\ \ \ \ \ \ \ \ if\ \{\[isKeyboard\ \$device\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[file\ readable\ \$device\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"keyboard:\ Device\ \$device\ is\ not\ readable.\ Attempting\ to\ change\ permissions.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Attempt\ to\ change\ permissions\ so\ that\ the\ file\ can\ be\ read\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ chmod\ +r\ \$device\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ keyboards\ \$device\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$keyboards\n\}\n\nset\ keyboardDevices\ \[walkInputEventPaths\]\nforeach\ keyboard\ \$keyboardDevices\ \{\n\ \ \ \ Claim\ \$keyboard\ is\ a\ keyboard\ device\n\}\n\n#\ backwards\ compatibility\nWhen\ /page/\ is\ a\ keyboard\ with\ path\ /keyboard/\ \{\n\ \ \ \ Claim\ \$page\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ us\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ device\ \{\n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/esc-pos.folk does not run} are (
[ m45:0 (s71:0) ]
[ m298:0 (s465:0 s471:0) ]
)when the collected results for {/any/ wishes program builtin-programs/esc-pos.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/esc-pos.folk programCode When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\n\ \ \ \ fn\ printProgram\ \{printer\ id\ code\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ writeFolkFile\ \$id\ \$code\n\ \ \ \ \ \ \ \ writeMetaFile\ \$printer\ \$id\n\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ is\ at\ /address/\n\ \ \ \ \ \ \ \ set\ printerSocket\ \[socket\ stream\ \$\{address\}:9100\]\n\n\ \ \ \ \ \ \ \ fconfigure\ \$printerSocket\ -translation\ binary\ -buffering\ none\n\ \ \ \ \ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[init\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[tag\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\])\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 2\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[cut\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$printerSocket\ \[render\ \$template\]\n\ \ \ \ \ \ \ \ close\ \$printerSocket\n\ \ \ \ \}\n\n\ \ \ \ fn\ render\ \{template\}\ \{\n\ \ \ \ \ \ \ \ set\ trimmed\ \[lmap\ line\ \[split\ \$template\ \"\\n\"\]\ \{\ string\ trim\ \$line\ \}\]\n\ \ \ \ \ \ \ \ set\ singleLine\ \[join\ \$trimmed\ \"\"\]\n\ \ \ \ \ \ \ \ return\ \[uplevel\ \[list\ subst\ \$singleLine\]\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeFolkFile\ \{id\ code\}\ \{\n\ \ \ \ \ \ \ \ set\ folkFile\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$folkFile\ \$code\n\ \ \ \ \ \ \ \ close\ \$folkFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeMetaFile\ \{printer\ id\}\ \{\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ has\ tag\ geometry\ /geometry/\n\ \ \ \ \ \ \ \ set\ metaFile\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$metaFile\ \[subst\ \{Claim\ tag\ \\\$this\ has\ geometry\ \{\$geometry\}\}\]\n\ \ \ \ \ \ \ \ close\ \$metaFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ cut\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1dV\\x0\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ feed\ n\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"\\x1b\\x64%c\"\ \$n\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ init\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1b\\x40\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ raw\ number\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"%c\"\ \$number\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ scaledAprilTag\ \{id\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ \ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\ \}\ \{\$i\ <\ \$scale\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \[expr\ \{\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ !=\ 255\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \{*\}\[lrepeat\ \$scale\ \$bit\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$tagBits\n\ \ \ \ \}\n\n\ \ \ \ #\ scale\ must\ be\ divisible\ by\ 4\ so\ width\ will\ be\ divisible\ by\ 8\n\ \ \ \ fn\ tag\ \{id\ \{scale\ 12\}\}\ \{\n\ \ \ \ \ \ \ \ set\ tagBits\ \[scaledAprilTag\ \$id\ \$scale\]\n\n\ \ \ \ \ \ \ \ set\ width\ \[expr\ \{10\ *\ \$scale\}\]\n\ \ \ \ \ \ \ \ set\ xL\ \[expr\ \{\$width\ /\ 8\}\]\ \ \ \;#\ width\ in\ bytes\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yL\ \[expr\ \{\$width\ %\ 256\}\]\ \;#\ height\ in\ lines\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yH\ \[expr\ \{\$width\ /\ 256\}\]\ \;#\ height\ in\ lines\ (high\ byte)\n\n\ \ \ \ \ \ \ \ return\ \"\\x1dv0\\x03\[raw\ \$xL\]\\x00\[raw\ \$yL\]\[raw\ \$yH\]\[binary\ format\ B*\ \[join\ \$tagBits\ \"\"\]\]\"\n\ \ \ \ \}\n\n\ \ \ \ Subscribe:\ print\ program\ /id/\ on\ receipt\ printer\ /printer/\ with\ code\ /code/\ \{\n\ \ \ \ \ \ \ \ printProgram\ \$printer\ \$id\ \$code\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk does not run (
[ m46:0 (s73:0) ]
[ m332:0 (s525:0 s530:0) ]
)when the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/tags-geometry.folk programCode When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ scaled\ by\ x\ /xScale/\ y\ /yScale/\ \{\n\ \ \ \ proc\ extractMm\ \{mm\}\ \{\n\ \ \ \ \ \ \ \ regexp\ \{(\[0-9.\]+)mm\}\ \$mm\ ->\ extracted\n\ \ \ \ \ \ \ \ return\ \$extracted\n\ \ \ \ \}\n\n\ \ \ \ set\ tagSize\ \[extractMm\ \[dict\ get\ \$defaultGeom\ tagSize\]\]\n\ \ \ \ set\ left\ \[extractMm\ \[dict\ get\ \$defaultGeom\ left\]\]\n\ \ \ \ set\ right\ \[extractMm\ \[dict\ get\ \$defaultGeom\ right\]\]\n\ \ \ \ set\ top\ \[extractMm\ \[dict\ get\ \$defaultGeom\ top\]\]\n\ \ \ \ set\ bottom\ \[extractMm\ \[dict\ get\ \$defaultGeom\ bottom\]\]\n\n\ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\n\ \ \ \ set\ right\ \$(\$right\ +\ (\$width\ *\ \$xScale\ -\ \$width))mm\n\ \ \ \ set\ bottom\ \$(\$bottom\ +\ (\$height\ *\ \$yScale\ -\ \$height))mm\n\n\ \ \ \ set\ newGeom\ \[list\ tagSize\ \$\{tagSize\}mm\ left\ \$\{left\}mm\ right\ \$\{right\}mm\ top\ \$\{top\}mm\ bottom\ \$\{bottom\}mm\]\n\n\ \ \ \ Claim\ tag\ \$program\ has\ geometry\ \$newGeom\n\}\n\nWhen\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /tag/\ has\ resolved\ geometry\ \{\n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/title.folk does not run} are /_ (
[ m49:0 (s74:0) ]
[ m342:0 (s533:0 s538:0) ]
)when the collected results for {/any/ wishes program builtin-programs/title.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/title.folk programCode #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ titled\ \"This\ is\ a\ tag\"\n#\ Wish\ \$this\ is\ footnoted\ \"This\ is\ a\ footnote\"\n#\ Wish\ \$this\ is\ right-margined\ \"This\ is\ right-margined\ text\"\n#\ Wish\ \$this\ is\ left-margined\ \"This\ is\ left-margined\ text\"\n\nWhen\ /thing/\ has\ quad\ /quad/\ \{\n\ \ \ \ Claim\ -keep\ 50ms\ \$thing\ has\ a\ quad\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /thing/\ has\ a\ quad\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk does no (
[ m31:0 (s56:0) ]
[ m222:0 (s339:0 s345:0) ]
)when the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/keyboard-shortcuts.folk programCode {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard-shortcuts.folk, match m10029:6: Failed to restart folk.service: Interactive authentication required.
#
# TODO: Figure out how to do this with less powerful permissions than `sudo`. (@cwervo)
# Keyboard shortcuts
# ---
# Alt + Esc: Restart Folk
# Alt + F1: Stop Folk completely (note: need to ssh to restart Folk)
# Alt-Esc on most keyboards
Subscribe: keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
}
# Console_1 corresponds to Alt-F1 on most keyboards
Subscribe: keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk does not run} (
[ m35:0 (s66:0) ]
[ m290:0 (s453:0 s460:0) ]
)when the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/terminal-ui.folk programCode {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/connections.folk does not run} (
[ m48:0 (s75:0) ]
[ m344:0 (s535:0 s545:0) ]
)when the collected results for {/any/ wishes program builtin-programs/connections.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/connections.folk programCode #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connected\ to\ \$tag2\"\ or\ \"Wish\ \$tag\ is\ dynamically\ connected\ to\ \$tag2\"\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ dynamically\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ sub\ \$sink\ \$source\]\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ grey\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ set\ c\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 2\ color\ \$color\ layer\ \$layer\n\ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ 30\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\}\n\nset\ speed\ 75\nset\ spacing\ 50\nset\ maxsize\ 25\n\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ normalize\ \[vec2\ sub\ \$sink\ \$source\]\]\n\ \ \ set\ distance\ \[vec2\ distance\ \$sink\ \$source\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\ \n\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ lassign\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\ cx\ cy\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 1\ color\ \$color\ layer\ \$layer\n\ \ \ \n\ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ set\ offset\ \[expr\ \{round(\$t*\$speed)\ %\ \$spacing\}\]\n\ \ \ \ \ set\ count\ \[expr\ \{round(\$distance\ /\ \$spacing)\}\]\n\n\ \ \ \ \ for\ \{set\ p\ \$offset\}\ \{\$p\ <\ \$distance\}\ \{incr\ p\ \$spacing\}\ \{\n\ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$source\ \[vec2\ scale\ \$direction\ \$p\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[expr\ \{min(\$maxsize,\ 0.20*min(\$p,\ \$distance\ -\ \$p))\}\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ \$s\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/unix-commands.folk does not run (
[ m51:0 (s79:0) ]
[ m346:0 (s541:0 s550:0) ]
)when the collected results for {/any/ wishes program builtin-programs/unix-commands.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/unix-commands.folk programCode #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ Wish\ \$this\ runs\ Unix\ command\ \"journalctl\"\ with\ arguments\ \[list\ \"-f\"\ \"-u\"\ \"folk\"\]\nWhen\ /someone/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ with\ arguments\ /args/\ \{\n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n\}\n\n#\ Convenience\ wrapper\ for\ commands\ without\ arguments\nWhen\ /wisher/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ \{\n\tSay\ \$wisher\ wishes\ \$p\ runs\ Unix\ command\ \$command\ with\ arguments\ \[list\]\n\}\n\n#\ When\ /someone/\ wishes\ /p/\ tests\ Unix\ commands\ \{\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"curl\"\ with\ arguments\ \[list\ \"-fsS\"\ \"http://wttr.in/Baltimore?format='%l:+%C'\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"-sSh\"\ \"/home/folk/folk2\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ping\"\ with\ arguments\ \[list\ \"google.com\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"sh\"\ with\ arguments\ \[list\ \"-c\"\ \"while\ :\;\ do\ date\ +%s.%3N\;\ sleep\ 0.5\;\ done\"\]\n\n#\ \t#\ Test\ error\ handling:\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"/nonexistent/path\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"exec\"\ with\ arguments\ \[list\ \"/dev/null\"\]\n\n#\ \tWhen\ \$p\ has\ Unix\ error\ output\ /errorSummary/\ \{\n#\ \t\tputs\ \"errorSummary:\ \$errorSummary\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$errorSummary\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ red\n#\ \t\}\n\n#\ \tWhen\ \$p\ has\ Unix\ output\ lines\ /outputLines/\ \{\n#\ \t\tputs\ \"outputLines:\ \$outputLines\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$outputLines\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ green\n#\ \t\}\n#\ \}} {}}
when the collected results for {/any/ wishes program builtin-programs/fswatch.folk does not run} are (
[ m54:0 (s83:0) ]
[ m362:0 (s568:0 s573:0) ]
)when the collected results for {/any/ wishes program builtin-programs/fswatch.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/fswatch.folk programCode #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ --recursive\ --event\ Updated\ --event\ Created\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ builtin-programs\ \$::env(HOME)/folk-data/local-program\ \$::env(PWD)/user-programs\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -buffering\ line\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ if\ \{\[gets\ \$fd\ line\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"fswatch:\ fswatch\ failed.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{builtin-programs\\/.*\$\}\ \$line\ changedPath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ changedPath\ \$line\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ changedFilename\ \[file\ tail\ \$changedPath\]\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$changedFilename\ 0\]\ eq\ \".\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$changedFilename\ 0\]\ eq\ \"#\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[file\ extension\ \$changedFilename\]\ ne\ \".folk\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ \"fswatch:\ \$changedPath\ updated,\ ignoring.\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"fswatch:\ \$changedPath\ updated,\ reloading.\"\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$changedPath\ r\]\;\ set\ programCode\ \[read\ \$fp\]\;\ close\ \$fp\n\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 100ms\ -on\ boot.folk\ -key\ \[list\ \$changedPath\ code\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$changedPath\ has\ program\ code\ \$programCode\n\ \ \ \ \}\n\}\ on\ error\ err\ \{\n\ \ \ \ puts\ stderr\ \"fswatch:\ Warning:\ could\ not\ invoke\ `fswatch`\ (\$err).\"\n\ \ \ \ puts\ stderr\ \"fswatch:\ Will\ not\ watch\ builtin-programs\ for\ changes.\"\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/editor-control.folk does not ru (
[ m55:0 (s85:0) ]
[ m375:0 (s593:0 s598:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor-control.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/editor-control.folk programCode When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \"/editor-control\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ html\ \{\n<!DOCTYPE\ html>\n<html\ lang=\"en\">\n\ \ \ \ <head>\n\ \ \ \ \ \ \ \ <meta\ charset=\"utf-8\"\ />\n\ \ \ \ \ \ \ \ <title>Editor\ copy/paste</title>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ </head>\n\ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ \ \ \ \ Select\ a\ keyboard:\ <select\ id=\"keyboard-select\"></select>\n\ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"120\"\ rows=\"40\"></textarea>\n\ \ \ \ \ \ \ \ <script>\nconst\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\nconst\ keyboardSelect\ =\ document.querySelector(\"#keyboard-select\")\;\nconst\ textarea\ =\ document.querySelector(\"#code\")\;\n\nvar\ currentKeyboard\ =\ null\;\nvar\ programCode\ =\ \"\"\;\ //\ not\ the\ same\ as\ editor\ code\nvar\ cursorPosition\ =\ \[0,\ 0\]\;\n\n//\ temporarily\ disable\ event\ processing\ after\ sending\ new\ code\ to\ prevent\ recursive\ event\ sends\nvar\ allowLocalEventsToProcess\ =\ true\;\nvar\ allowRemoteEventsToProcess\ =\ true\;\nvar\ _remoteTimoutHandle\;\nvar\ _localTimeoutHandle\;\nfunction\ disableRemoteEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_remoteTimoutHandle)\ clearTimeout(_remoteTimoutHandle)\;\n\ \ \ \ allowRemoteEventsToProcess\ =\ false\;\n\n\ \ \ \ _remoteTimoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowRemoteEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ disableLocalEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_localTimeoutHandle)\ clearTimeout(_localTimeoutHandle)\;\n\ \ \ \ allowLocalEventsToProcess\ =\ false\;\n\n\ \ \ \ _localTimeoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowLocalEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ updateProgramCode()\ \{\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ currentCode\ =\ textarea.value\;\n\ \ \ \ programCode\ =\ currentCode\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{cursorPosition\[0\]\}\ \$\{cursorPosition\[1\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\nfunction\ updateCursorAndCode(ev)\ \{\n\ \ \ \ if\ (!allowLocalEventsToProcess)\ return\;\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ newCode\ =\ ev.target.value\;\n\n\ \ \ \ //\ figure\ out\ cursor\ position\n\ \ \ \ const\ currentPosition\ =\ textarea.selectionStart\;\n\ \ \ \ const\ linesBefore\ =\ newCode.substring(0,\ currentPosition).split(\"\\n\")\;\n\ \ \ \ const\ y\ =\ linesBefore.length\ -\ 1\;\n\ \ \ \ const\ x\ =\ linesBefore\[linesBefore.length\ -\ 1\].length\;\n\n\ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{x\}\ \$\{y\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(programCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(newCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\ntextarea.addEventListener(\"input\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"selectionchange\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"keydown\",\ ev\ =>\ \{\n\ \ \ \ if(ev.keyCode\ ===\ 83\ /*\ s\ */\ &&\ (navigator.platform.match(\"Mac\")\ ?\ ev.metaKey\ :\ ev.ctrlKey))\ \{\n\ \ \ \ \ \ \ \ ev.preventDefault()\;\n\ \ \ \ \ \ \ \ updateProgramCode()\;\n\ \ \ \ \}\n\})\;\n\nvar\ lastKeyboard\;\ //\ to\ clean\ up\ the\ previous\ keyboard\ when\ another\ is\ picked\nasync\ function\ selectKeyboard(\{\ page,\ kbPath\ \})\ \{\n\ \ \ \ if\ (lastKeyboard)\ lastKeyboard.stop()\;\n\n\ \ \ \ currentKeyboard\ =\ \{\ page,\ kbPath\ \}\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ lastKeyboard\ =\ await\ ws.watch(`\$\{id\}\ has\ base64\ editor\ code\ /editorCode/\ program\ code\ /programCode/\ &\ the\ \$\{kbPath\}\ cursor\ is\ /cursor/`,\ \{\n\ \ \ \ \ \ \ \ add:\ (\{\ editorCode,\ programCode:\ _programCode,\ cursor\ \})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (!allowRemoteEventsToProcess)\ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ disableLocalEventProcessing(500)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ programCode\ =\ atob(_programCode)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ editorCode\ =\ atob(editorCode)\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.value\ =\ editorCode\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ figure\ out\ where\ the\ cursor\ is\n\ \ \ \ \ \ \ \ \ \ \ \ let\ \[x,\ y\]\ =\ loadList(cursor)\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ parseInt(x)\;\ y\ =\ parseInt(y)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ const\ lines\ =\ editorCode.split(\"\\n\")\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ let\ pos\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (let\ i\ =\ 0\;\ i\ <\ y\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ lines\[i\].length\ +\ 1\;\ //\ +\ 1\ for\ newline\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ x\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.focus()\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionStart\ =\ pos\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionEnd\ =\ pos\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \})\;\n\}\n\n//\ update\ keyboard\ list\ as\ it\ changes\nws.watchCollected(\"/page/\ is\ an\ editor\ &\ /page/\ is\ a\ keyboard\ with\ path\ /kbPath/\",\ keyboards\ =>\ \{\n\ \ \ \ keyboardSelect.innerHTML\ =\ \"\"\;\n\n\ \ \ \ for\ (let\ keyboard\ of\ keyboards)\ \{\n\ \ \ \ \ \ \ \ let\ \{page,\ kbPath\}\ =\ keyboard\;\n\ \ \ \ \ \ \ \ keyboardSelect.innerHTML\ +=\ `<option\ value=\"\$\{JSON.stringify(keyboard)\}\">\$\{page\}\ (\$\{kbPath\})</option>`\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (keyboards.length\ ===\ 1)\ \{\n\ \ \ \ \ \ \ \ selectKeyboard(keyboards\[0\])\;\n\ \ \ \ \}\n\})\;\n\n//\ fired\ when\ selected\ keyboard\ changes\nkeyboardSelect.addEventListener(\"input\",\ (ev)\ =>\ \{\n\ \ \ \ selectKeyboard(JSON.parse(ev.target.value))\;\n\})\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/display-saver.folk does not run (
[ m56:0 (s86:0) ]
[ m377:0 (s591:0 s594:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display-saver.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/display-saver.folk programCode When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/image.folk does not run} a (
[ m59:0 (s92:0) ]
[ m390:0 (s612:0 s614:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/image.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/image.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*jpg\"\ \$im\]\ ||\ \[string\ match\ \"*jpeg\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$jpegLib\ loadJpeg\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ jpegLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ png\ library\ is\ /pngLib/\ \{\n\ \ \ \ fn\ pngLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*png\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$pngLib\ loadPng\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ pngLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ \ \ fn\ gifLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ upvar\ coerceToImage\ coerceToImage\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gif\ \[\$gifLib\ loadGif\ \$im\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$coerceToImage\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \[lindex\ \[dict\ get\ \$gif\ frames\]\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ WARNING:\ This\ is\ not\ an\ Image\ object\ --\ it's\ a\ Gif\n\ \ \ \ \ \ \ \ \ \ \ \ #\ object\ and\ requires\ special\ handling\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$gif\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ gifLoader\]\ is\ an\ image\ loader\n\}\n\n\nWhen\ the\ collected\ results\ for\ \{/loader/\ is\ an\ image\ loader\}\ are\ /loaders/\ \{\n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"image\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.01)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ return\ texColor\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\}\}\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ image\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ displays\ image\ /impath/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n\}\n\nWhen\ /someone/\ wishes\ /p/\ displays\ image\ /im/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ scale\ 1.0\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk does not ru (
[ m61:0 (s93:0) ]
[ m397:0 (s622:0 s623:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/apriltags.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ vec4\ background\n\ \ \ \ \ uvec4\ tagBitsVec\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\n\ \ \ \ \ \ \ \ int\ x\ =\ int(uv.x\ *\ 10)\;\ int\ y\ =\ int(uv.y\ *\ 10)\;\n\ \ \ \ \ \ \ \ int\ bitIdx\ =\ y\ *\ 10\ +\ x\;\n\ \ \ \ \ \ \ \ uint\ bit\ =\ (tagBitsVec\[bitIdx\ /\ 32\]\ >>\ (bitIdx\ %\ 32))\ &\ 0x1\;\n\ \ \ \ \ \ \ \ return\ bit\ ==\ 1\ ?\ background\ :\ vec4(0,\ 0,\ 0,\ 1)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /writableTexture/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ AprilTag\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/fill.folk does not run} ar (
[ m63:0 (s96:0) ]
[ m407:0 (s647:0 s649:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/fill.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/fill.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](p0,\ p1,\ p2,\ p0,\ p0,\ p0)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ return\ color\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ \{\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n\nWhen\ /someone/\ wishes\ /page/\ is\ filled\ with\ /...options/\ &\\\n\ \ \ \ \ /page/\ has\ region\ /region/\ \{\n\ \ set\ points\ \[region\ vertices\ \$region\]\n\ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ \{*\}\$options\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk does not (
[ m65:0 (s100:0) ]
[ m409:0 (s651:0 s656:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/dashed-line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\n\ \ \ \ \ float\ dashlength\ float\ dashoffset\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\n\ \ \ \ \ \ \ \ //\ How\ far\ are\ we\ along\ the\ line?\ (in\ pixels)\n\ \ \ \ \ \ \ \ float\ t\ =\ dot(surfaceXy.xy\ -\ from,\ to\ -\ from)\ /\ l\ +\ dashoffset\;\n\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0\ &&\ floor(mod(t\ /\ dashlength,\ 2.0))\ ==\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ dashed\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/line.folk does not run} ar (
[ m67:0 (s102:0) ]
[ m416:0 (s667:0 s673:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/line.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/gif.folk does not run} are (
[ m69:0 (s105:0) ]
[ m426:0 (s679:0 s682:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/gif.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/gif.folk programCode When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/circle.folk does not run} (
[ m70:0 (s107:0) ]
[ m434:0 (s695:0 s698:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/circle.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/circle.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ center\ float\ radius\ float\ thickness\ vec4\ color\ int\ filled\}\ \{\n\ \ \ \ \ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ center\ +\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r)\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(surfaceXy.xy\ -\ center)\ -\ radius\;\n\ \ \ \ \ \ \ \ if\ (filled\ ==\ 1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ circle\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk does not ru (
[ m74:0 (s112:0) ]
[ m440:0 (s705:0 s711:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/color-map.folk programCode {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr {($color >> 8) & 0xFF}]
set r [expr {($color >> 16) & 0xFF}]
return [list [/ $r 255.0] [/ $g 255.0] [/ $b 255.0] 1.0]
}
set colors {
aliceblue F0F8FF
antiquewhite FAEBD7
aqua 00FFFF
aquamarine 7FFFD4
azure F0FFFF
beige F5F5DC
bisque FFE4C4
black 000000
blanchedalmond FFEBCD
blue 0000FF
blueviolet 8A2BE2
brown A52A2A
burlywood DEB887
cadetblue 5F9EA0
chartreuse 7FFF00
chocolate D2691E
coral FF7F50
cornflowerblue 6495ED
cornsilk FFF8DC
crimson DC143C
cyan 00FFFF
darkblue 00008B
darkcyan 008B8B
darkgoldenrod B8860B
darkgray A9A9A9
darkgreen 006400
darkgrey A9A9A9
darkkhaki BDB76B
darkmagenta 8B008B
darkolivegreen 556B2F
darkorange FF8C00
darkorchid 9932CC
darkred 8B0000
darksalmon E9967A
darkseagreen 8FBC8F
darkslateblue 483D8B
darkslategray 2F4F4F
darkslategrey 2F4F4F
darkturquoise 00CED1
darkviolet 9400D3
deeppink FF1493
deepskyblue 00BFFF
dimgray 696969
dimgrey 696969
dodgerblue 1E90FF
firebrick B22222
floralwhite FFFAF0
forestgreen 228B22
fuchsia FF00FF
gainsboro DCDCDC
ghostwhite F8F8FF
gold FFD700
goldenrod DAA520
gray 808080
green 008000
greenyellow ADFF2F
grey 808080
honeydew F0FFF0
hotpink FF69B4
indianred CD5C5C
indigo 4B0082
ivory FFFFF0
khaki F0E68C
lavender E6E6FA
lavenderblush FFF0F5
lawngreen 7CFC00
lemonchiffon FFFACD
lightblue ADD8E6
lightcoral F08080
lightcyan E0FFFF
lightgoldenrodyellow FAFAD2
lightgray D3D3D3
lightgreen 90EE90
lightgrey D3D3D3
lightpink FFB6C1
lightsalmon FFA07A
lightseagreen 20B2AA
lightskyblue 87CEFA
lightslategray 778899
lightslategrey 778899
lightsteelblue B0C4DE
lightyellow FFFFE0
lime 00FF00
limegreen 32CD32
linen FAF0E6
magenta FF00FF
maroon 800000
mediumaquamarine 66CDAA
mediumblue 0000CD
mediumorchid BA55D3
mediumpurple 9370DB
mediumseagreen 3CB371
mediumslateblue 7B68EE
mediumspringgreen 00FA9A
mediumturquoise 48D1CC
mediumvioletred C71585
midnightblue 191970
mintcream F5FFFA
mistyrose FFE4E1
moccasin FFE4B5
navajowhite FFDEAD
navy 000080
oldlace FDF5E6
olive 808000
olivedrab 6B8E23
orange FFA500
orangered FF4500
orchid DA70D6
palegoldenrod EEE8AA
palegreen 98FB98
paleturquoise AFEEEE
palevioletred DB7093
papayawhip FFEFD5
peachpuff FFDAB9
peru CD853F
pink FFC0CB
plum DDA0DD
powderblue B0E0E6
purple 800080
rebeccapurple 663399
red FF0000
rosybrown BC8F8F
royalblue 4169E1
saddlebrown 8B4513
salmon FA8072
sandybrown F4A460
seagreen 2E8B57
seashell FFF5EE
sienna A0522D
silver C0C0C0
skyblue 87CEEB
slateblue 6A5ACD
slategray 708090
slategrey 708090
snow FFFAFA
springgreen 00FF7F
steelblue 4682B4
tan D2B48C
teal 008080
thistle D8BFD8
tomato FF6347
turquoise 40E0D0
violet EE82EE
wheat F5DEB3
white FFFFFF
whitesmoke F5F5F5
yellow FFFF00
yellowgreen 9ACD32
}
set colorMap [dict create]
foreach {color hex} $colors {
dict set colorMap $color [hexcolor $hex]
}
Claim the color map is $colorMap
}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk does not run (
[ m75:0 (s116:0) ]
[ m446:0 (s718:0 s722:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/image/gif-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/text.folk does not run} ar (
[ m77:0 (s117:0) ]
[ m450:0 (s728:0 s734:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/text.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/draw/text.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk does not ru (
[ m79:0 (s121:0) ]
[ m451:0 (s725:0 s730:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/image/jpeg-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk does not r (
[ m81:0 (s123:0) ]
[ m457:0 (s736:0 s740:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/image/image-lib.folk programCode {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width;
uint32_t height;
int components;
uint32_t bytesPerRow;
// Weird: this can be mutated if you want the image to be
// reloaded into the GPU.
uint64_t uniq;
uint8_t* data;
}
# Note that this returns an image whose lifetime is tied to the original image.
$cc proc slice {Image im double x double y double subwidth double subheight} Image {
uint8_t *subdata = im.data + (int)y*im.bytesPerRow + (int)x*im.components;
return (Image) {
.width = (uint32_t)subwidth,
.height = (uint32_t)subheight,
.components = im.components,
.bytesPerRow = im.bytesPerRow,
.data = subdata,
.uniq = im.uniq
};
}
$cc proc imageNew {int width int height int components int uniq} Image {
uint8_t* data = malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data,
.uniq = uniq
};
}
$cc proc imageFree {Image image} void {
free(image.data);
}
# Note that this returns a fresh (copied) image. imVertices are
# coordinates in im, clockwise from top-left.
$cc proc warpQuad {Image im double[4][2] imVertices
int outWidth int outHeight} Image {
if (outWidth <= 0 || outHeight <= 0 ||
outWidth > (int)im.width * 4 || outHeight > (int)im.height * 4) {
FOLK_ERROR("warpQuad: bad dimensions %d x %d (source %d x %d)",
outWidth, outHeight, im.width, im.height);
}
Image out = imageNew(outWidth, outHeight, im.components, im.uniq);
// imVertices are clockwise from top-left: [TL, TR, BR, BL]
double tlX = imVertices[0][0], tlY = imVertices[0][1];
double trX = imVertices[1][0], trY = imVertices[1][1];
double brX = imVertices[2][0], brY = imVertices[2][1];
double blX = imVertices[3][0], blY = imVertices[3][1];
// For each output pixel, find corresponding source pixel using bilinear mapping
double invW = (outWidth > 1) ? 1.0 / (outWidth - 1) : 0.0;
double invH = (outHeight > 1) ? 1.0 / (outHeight - 1) : 0.0;
for (int y = 0; y < outHeight; y++) {
// Hoist v and y-dependent edge coords outside x-loop
double v = y * invH;
double leftX = tlX + v * (blX - tlX);
double leftY = tlY + v * (blY - tlY);
double rightX = trX + v * (brX - trX);
double rightY = trY + v * (brY - trY);
double stepX = (rightX - leftX) * invW;
double stepY = (rightY - leftY) * invW;
uint8_t *dstRow = out.data + y * out.bytesPerRow;
double srcX = leftX, srcY = leftY;
for (int x = 0; x < outWidth; x++, srcX += stepX, srcY += stepY) {
uint8_t *dstPixel = dstRow + x * out.components;
int ix = (int)srcX;
int iy = (int)srcY;
// Fixed-point fractions (0..255)
int fx = (int)((srcX - ix) * 256);
int fy = (int)((srcY - iy) * 256);
if (ix >= 0 && ix < (int)im.width - 1 && iy >= 0 && iy < (int)im.height - 1) {
uint8_t *p00 = im.data + iy * im.bytesPerRow + ix * im.components;
uint8_t *p10 = p00 + im.components;
uint8_t *p01 = p00 + im.bytesPerRow;
uint8_t *p11 = p01 + im.components;
for (int c = 0; c < im.components; c++) {
int top = p00[c] + ((fx * (p10[c] - p00[c])) >> 8);
int bot = p01[c] + ((fx * (p11[c] - p01[c])) >> 8);
dstPixel[c] = (uint8_t)(top + ((fy * (bot - top)) >> 8));
}
} else if (ix >= 0 && ix < (int)im.width && iy >= 0 && iy < (int)im.height) {
uint8_t *srcPixel = im.data + iy * im.bytesPerRow + ix * im.components;
for (int c = 0; c < im.components; c++) {
dstPixel[c] = srcPixel[c];
}
} else {
for (int c = 0; c < im.components; c++) {
dstPixel[c] = 0;
}
}
}
}
return out;
}
set imageLib [$cc compile]
Claim the image library is $imageLib
fn defineImageArgtype {uvx} {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
}
Claim the image uvx argtype definer is [fn defineImageArgtype]
}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk does not run (
[ m82:0 (s125:0) ]
[ m476:0 (s758:0 s761:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/image/png-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/print/print.folk does not run} (
[ m84:0 (s128:0) ]
[ m474:0 (s760:0 s764:0) ]
)when the collected results for {/any/ wishes program builtin-programs/print/print.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/print/print.folk programCode #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ from\ the\ Web\ UI,\ or\ declare\ it\ using\ Folk:\n#\n#\ \ \ \ \ Assert\ \$::thisNode\ claims\ printer\ \"printer-name\"\ is\ a\ cups\ printer\ with\ url\ \"http://url/ipp/print\"\ driver\ \"everywhere\"\n#\n#\ Lastly,\ you\ need\ to\ declare\ a\ default\ printer\ and\ default\ paper\ format:\n#\ (make\ sure\ that\ the\ default\ printer\ supports\ the\ default\ paper\ format)\n#\n#\ \ \ \ \ Claim\ printer\ my-printer\ is\ the\ default\ printer\n#\ \ \ \ \ Claim\ paper\ format\ a4\ is\ the\ default\ paper\ format\n\nClaim\ the\ paper\ formats\ are\ \{\n\ \ \ \ letter\ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\ \ \ \ a4\ \ \ \ \ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{595\ 842\}\}\n\ \ \ \ indexcard\ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\}\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n\}\n\nSubscribe:\ print\ pdf\ /pdfPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk does not run (
[ m88:0 (s134:0) ]
[ m477:0 (s759:0 s762:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/dep-graph.folk programCode set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ create\]\n\ \ \ \ foreach\ stmt\ \[Query!\ /...anything/\]\ \{\n\ \ \ \ \ \ \ \ set\ stmtRef\ \[dict\ get\ \$stmt\ __ref\]\n\ \ \ \ \ \ \ \ set\ label\ \[\$dbLib\ clause\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ label\ \[join\ \[lmap\ line\ \[split\ \$label\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ set\ label\ \[string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$label\]\]\n\ \ \ \ \ \ \ \ set\ stmtParentCount\ \[\$dbLib\ statementParentCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ stmtPtrCount\ \[\$dbLib\ statementPtrCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ \\\[label=\\\"\$stmtRef\ (\$stmtParentCount\ parents)\ (\$stmtPtrCount\ ptrs):\ \$label\\\"\\\]\;\"\n\n\ \ \ \ \ \ \ \ foreach\ childMatchRef\ \[\$dbLib\ childMatches\ \$db\ \$stmtRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ ->\ <\$childMatchRef>\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ matchRefs\ \$childMatchRef\ true\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ foreach\ \{matchRef\ _\}\ \$matchRefs\ \{\n\ \ \ \ \ \ \ \ set\ match\ \[\$dbLib\ matchAcq\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ if\ \{\$match\ eq\ \"(Match*)\ 0x0\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ set\ matchPtrCount\ \[\$dbLib\ matchPtrCount\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ set\ matchIsAlive\ \[\$dbLib\ matchIsAlive\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ \\\[label=\\\"\$matchRef\ (alive?\ \$matchIsAlive)\ (\$matchPtrCount)\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ childStatementRef\ \[\$dbLib\ childStatements\ \$db\ \$matchRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ ->\ <\$childStatementRef>\;\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$dbLib\ matchRel\ \$db\ \$match\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[join\ \$dot\ \"\\n\"\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWhen\ the\ db\ library\ is\ /dbLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/nav.folk does not run} are (
[ m89:0 (s135:0) ]
[ m494:0 (s785:0 s788:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/nav.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/nav.folk programCode {When the collected results for [list /someone/ wishes the web server handles route /route/ with /...options/] are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/setup.folk does not run} ar (
[ m91:0 (s139:0) ]
[ m499:0 (s804:0 s812:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/setup.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/setup.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handler\ \{\n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk does not r (
[ m94:0 (s144:0) ]
[ m505:0 (s805:0 s808:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/block-stats.folk programCode {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/textures.folk does not run} (
[ m96:0 (s146:0) ]
[ m504:0 (s807:0 s811:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/textures.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/textures.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ draw\ library\ is\ /drawLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ endcflags\ -lpng\n\ \ \ \ \$cc\ cflags\ -I./vendor\n\ \ \ \ \$cc\ endcflags\ \$vmaDll\n\ \ \ \ \$cc\ include\ <png.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ \ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ \ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ to\ make\ gpuLib\ extend\ properly\n\ \ \ \ \$cc\ typedef\ \{struct\ PushConstantsEncoder\}\ PushConstantsEncoder\n\ \ \ \ \$cc\ typedef\ \{struct\ Pipeline\}\ Pipeline\n\ \ \ \ \$cc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\ \ \ \ \$cc\ argtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ \ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ rtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ char\ buf\[100\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ extend\ \$gpuLib\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ extend\ \$gpuTextureLib\n\ \ \ \ \$cc\ proc\ texturesLibInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ volkInitialize()\;\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyTextureFromGpu\ \{GpuTextureHandle\ han\}\ Image\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ getGpuTexture(han)\;\n\ \ \ \ \ \ \ \ if\ (!block->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (Image)\{0\}\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ block->width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ block->height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\ //\ HACK:\ hard-coded\ for\ now\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ block->width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ malloc(block->width\ *\ block->height\ *\ 4)\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ size_t\ stagingBufferSize\ =\ block->width\ *\ block->height\ *\ 4\;\n\ \ \ \ \ \ \ \ createBuffer(stagingBufferSize,\ VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &stagingBuffer,\ &stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n\ \ \ \ \ \ \ \ \ \ \ \ .oldLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .image\ =\ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseMipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.levelCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ image\ to\ buffer\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferOffset\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferRowLength\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferImageHeight\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.mipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageOffset\ =\ \{0,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ .imageExtent\ =\ \{block->width,\ block->height,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdCopyImageToBuffer(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ ®ion\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ image\ layout\ back\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ VkFence\ fence\ =\ getFence()\;\n\ \ \ \ \ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ staging\ buffer\ back\ to\ CPU\n\ \ \ \ \ \ \ \ void*\ data\;\n\ \ \ \ \ \ \ \ vmaMapMemory(vmaGetAllocator(),\ stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ memcpy(im.data,\ data,\ stagingBufferSize)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ //\ Cleanup\ staging\ buffer\n\ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\ stagingBuffer,\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ struct\ WriteState\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ buffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t*\ size\;\ \n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ void\ pngWriteCallback(png_structp\ png_ptr,\ png_bytep\ data,\ png_size_t\ length)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ WriteState*\ state\ =\ (struct\ WriteState*)png_get_io_ptr(png_ptr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(state->buffer\ +\ *state->size,\ data,\ length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ *state->size\ +=\ length\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ imageToPngBuffer\ \{Image\ im\ size_t*\ outSize\}\ uint8_t*\ \{\n\ \ \ \ \ \ \ \ size_t\ bufferSize\ =\ im.width\ *\ im.height\ *\ im.components\ *\ 2\;\ //\ max\ size\ estimate\n\ \ \ \ \ \ \ \ uint8_t*\ buffer\ =\ malloc(bufferSize)\;\n\ \ \ \ \ \ \ \ *outSize\ =\ 0\;\n\n\ \ \ \ \ \ \ \ png_structp\ png_w\ =\ png_create_write_struct(PNG_LIBPNG_VER_STRING,\ NULL,\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (!png_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_infop\ info_w\ =\ png_create_info_struct(png_w)\;\n\ \ \ \ \ \ \ \ if\ (!info_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ struct\ WriteState\ state\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .buffer\ =\ buffer,\n\ \ \ \ \ \ \ \ \ \ \ \ .size\ =\ outSize\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ png_set_write_fn(png_w,\ &state,\ pngWriteCallback,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGBA,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGB,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_bytep*\ row_pointers\ =\ malloc(sizeof(png_bytep)\ *\ im.height)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ row_pointers\[y\]\ =\ im.data\ +\ y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_set_rows(png_w,\ info_w,\ row_pointers)\;\n\ \ \ \ \ \ \ \ png_write_png(png_w,\ info_w,\ PNG_TRANSFORM_IDENTITY,\ NULL)\;\n\n\ \ \ \ \ \ \ \ free(row_pointers)\;\n\ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\n\ \ \ \ \ \ \ \ *outSize\ =\ bufferSize\;\n\ \ \ \ \ \ \ \ return\ buffer\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyAllTexturesFromGpu\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (getGpuTexture(i)->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Image\ im\ =\ copyTextureFromGpu(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pngSize\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ pngData\ =\ imageToPngBuffer(im,\ &pngSize)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_ObjPrintf(\"Image\ %d\ (%d\ x\ %d)\",\ i,\ im.width,\ im.height))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_NewStringObj(interp,\ (char*)pngData,\ pngSize))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(pngData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(im.data)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ set\ texturesLib\ \[\$cc\ compile\]\n\ \ \ \ \$texturesLib\ texturesLibInit\n\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/textures\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ package\ require\ base64\n\n\ \ \ \ \ \ \ \ set\ images\ \[\$texturesLib\ copyAllTexturesFromGpu\]\n\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>Textures</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ img\ \{\ max-width:\ 100%\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{description\ imageData\}\ \$images\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ b64\ \[binary\ encode\ base64\ \$imageData\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \{<div><p>%s</p><img\ src=\"data:image/png\;base64,%s\"></div>\}\ \$description\ \$b64\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/program.folk does not run} (
[ m97:0 (s148:0) ]
[ m521:0 (s827:0 s831:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/program.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/program.folk programCode {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/holds.folk does not run} ar (
[ m98:0 (s150:0) ]
[ m528:0 (s834:0 s837:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/holds.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/holds.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk does not run} a (
[ m100:0 (s152:0) ]
[ m536:0 (s851:0 s855:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/db-lib.folk programCode {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
$cc include "db.h"
$cc include "common.h"
$cc include "vendor/stb_ds.h"
$cc code {
typedef struct ListOfEdgeTo {
size_t capacityEdges;
size_t nEdges; // This is an estimate.
uint64_t edges[];
} ListOfEdgeTo;
typedef struct GenRc {
int16_t rc;
int gen: 15;
bool alive: 1;
} GenRc;
#include <pthread.h>
}
set dbCFd [open "db.c" r]; set dbC [read $dbCFd]; close $dbCFd
$cc code [lindex [regexp -inline {typedef struct Destructor \{.*\} Destructor;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct DestructorSet \{.*\} DestructorSet;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Statement \{.*\} Statement;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Match \{.*\} Match;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Hold \{.*\} Hold;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct StatementRefList \{.*\} StatementRefList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersionList \{.*\} AtomicallyVersionList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersion \{.*\} AtomicallyVersion;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Atomically \{.*\} Atomically;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Db \{.*\} Db;} $dbC] 0]
$cc argtype StatementRef { StatementRef $argname; sscanf(Jim_String($obj), "s%d:%d", &$argname.idx, &$argname.gen); }
$cc argtype MatchRef { MatchRef $argname; sscanf(Jim_String($obj), "m%d:%d", &$argname.idx, &$argname.gen); }
$cc proc clauseToJimObj {Clause* clause} Jim_Obj* {
Jim_Obj* termObjs[clause->nTerms];
for (int i = 0; i < clause->nTerms; i++) {
termObjs[i] = Jim_NewStringObj(interp, termPtr(clause->terms[i]),
termLen(clause->terms[i]));
}
return Jim_NewListObj(interp, termObjs, clause->nTerms);
}
$cc proc statementParentCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
int ret = stmt->parentCount;
statementRelease(db, stmt);
return ret;
}
$cc proc statementPtrCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
GenRc genRc = stmt->genRc;
int ret = genRc.rc - 1;
statementRelease(db, stmt);
return ret;
}
$cc proc clause {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewStringObj(interp, "(null)", -1); }
Jim_Obj* ret = clauseToJimObj(statementClause(stmt));
statementRelease(db, stmt);
return ret;
}
$cc proc childMatches {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewEmptyStringObj(interp); }
pthread_mutex_lock(&stmt->childMatchesMutex);
if (stmt->childMatches == NULL) {
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[stmt->childMatches->nEdges];
for (int i = 0; i < stmt->childMatches->nEdges; i++) {
MatchRef child = { .val = stmt->childMatches->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("m%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc matchAcq {Db* db MatchRef matchRef} Match* {
return matchAcquire(db, matchRef);
}
$cc proc matchRel {Db* db Match* match} void {
matchRelease(db, match);
}
$cc proc matchPtrCount {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int ret = genRc.rc - 1;
matchRelease(db, match);
return ret;
}
$cc proc matchIsAlive {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int alive = genRc.alive;
matchRelease(db, match);
return alive;
}
$cc code {
#define CHILD_STATEMENTS_REMOVING ((ListOfEdgeTo*)1)
}
$cc proc childStatements {Db* db MatchRef matchRef} Jim_Obj* {
Match* match = matchAcquire(db, matchRef);
if (match == NULL) { return Jim_NewStringObj(interp, "", -1); }
pthread_mutex_lock(&match->childStatementsMutex);
if (match->childStatements == NULL ||
match->childStatements == CHILD_STATEMENTS_REMOVING) {
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[match->childStatements->nEdges];
for (int i = 0; i < match->childStatements->nEdges; i++) {
StatementRef child = { .val = match->childStatements->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("s%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc countAliveStatements {Db* db} int {
int count = 0;
for (int i = 1; i < 65536; i++) { // slot 0 is reserved
GenRc genRc = db->statementPool[i].genRc;
if (genRc.alive) {
count++;
}
}
return count;
}
$cc proc holds {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->holdsMutex);
for (int i = 0; i < shlen(db->holds); i++) {
Hold* hold = &db->holds[i];
Statement* stmt = statementAcquire(db, hold->statement);
if (stmt == NULL) {
fprintf(stderr, "db-lib: holds: WARNING: held statement on (%s) is invalid! (s%d:%d)\n",
hold->key, hold->statement.idx, hold->statement.gen);
continue;
}
char* clauseStr = clauseToString(statementClause(stmt));
Jim_Obj* holdObjv[] = {
Jim_NewStringObj(interp, hold->key, -1),
Jim_NewIntObj(interp, hold->version),
Jim_ObjPrintf("s%d:%d", hold->statement.idx, hold->statement.gen),
Jim_NewStringObj(interp, clauseStr, -1)
};
statementRelease(db, stmt);
free(clauseStr);
Jim_Obj* holdObj = Jim_NewListObj(interp, holdObjv,
sizeof(holdObjv)/sizeof(holdObjv[0]));
Jim_ListAppendElement(interp, retObj, holdObj);
}
mutexUnlock(&db->holdsMutex);
return retObj;
}
$cc proc atomicallys {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->atomicallysMutex);
for (int i = 0; i < sizeof(db->atomicallys)/sizeof(db->atomicallys[0]); i++) {
Atomically* atomically = &db->atomicallys[i];
if (atomically->key == NULL) { continue; }
// Count versions in allVersions list
int versionCount = 0;
AtomicallyVersionList* vl = atomically->allVersions;
while (vl != NULL) {
versionCount++;
vl = vl->next;
}
// Get latest converged version info
int latestConvergedNumber = -1;
if (atomically->latestConvergedVersion != NULL) {
latestConvergedNumber = atomically->latestConvergedVersion->number;
}
Jim_Obj* atomicallyObjv[] = {
Jim_NewStringObj(interp, atomically->key, -1),
Jim_NewIntObj(interp, latestConvergedNumber),
Jim_NewIntObj(interp, versionCount)
};
Jim_Obj* atomicallyObj = Jim_NewListObj(interp, atomicallyObjv,
sizeof(atomicallyObjv)/sizeof(atomicallyObjv[0]));
Jim_ListAppendElement(interp, retObj, atomicallyObj);
}
mutexUnlock(&db->atomicallysMutex);
return retObj;
}
return [$cc compile]
}}]
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/threads.folk does not run} (
[ m102:0 (s155:0) ]
[ m540:0 (s854:0 s858:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/threads.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/threads.folk programCode set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ -I./vendor/tracy/public\n\ \ \ \ \$cc\ include\ \"workqueue.h\"\n\ \ \ \ \$cc\ include\ \"common.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ extern\ ThreadControlBlock\ threads\[\]\;\n\ \ \ \ \ \ \ \ extern\ int\ _Atomic\ threadCount\;\n\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ int\ unsafe_workQueueCopy(WorkQueueItem*\ into,\ int\ maxn,\ WorkQueue*\ q)\;\n\ \ \ \ \ \ \ \ extern\ void\ traceItem(char*\ buf,\ size_t\ bufsz,\ WorkQueueItem\ item)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ itemToStringObj(WorkQueueItem\ item)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ char\ buf\[10000\]\;\ traceItem(buf,\ sizeof(buf),\ item)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerTids\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ //\ Fallback\ on\ macOS,\ where\ we\ don't\ have\ /proc\ to\ query\ all\n\ \ \ \ \ \ \ \ //\ threads\ of\ the\ Folk\ process.\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ threads\[i\].tid))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfo\ \{int\ threadIndex\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ if\ (threadIndex\ >=\ threadCount\ ||\ threads\[threadIndex\].tid\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ThreadControlBlock\ *thread\ =\ &threads\[threadIndex\]\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ thread->currentItem\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\ Jim_NewStringObj(interp,\ \"op\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(item))\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ items\[100\]\;\n\ \ \ \ \ \ \ \ int\ nitems\ =\ unsafe_workQueueCopy(items,\ 100,\ thread->workQueue)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ workQueueObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nitems\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ workQueueObj,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(items\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"workQueue\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ workQueueObj)\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"isDeactivated\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ thread->isDeactivated))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"currentItemStartTimestamp\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ObjPrintf(\"%\"\ PRId64,\ thread->currentItemStartTimestamp))\;\n\n\ \ \ \ \ \ \ \ int64_t\ now\ =\ timestamp_get(thread->clockid)\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"elapsed\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ (double)(now\ -\ thread->currentItemStartTimestamp)\ /\ 1000.0))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_allocs\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_allocs))\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_frees\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_frees))\;\n\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfoFromTid\ \{int\ tid\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ ==\ tid)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ workerInfo(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #include\ \"vendor/c11-queues/mpmc_queue.h\"\n\ \ \ \ \ \ \ \ extern\ struct\ mpmc_queue\ globalWorkQueue\;\n\ \ \ \ \ \ \ \ extern\ _Atomic\ int\ globalWorkQueueSize\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ globalWorkQueueAvailable\ \{\}\ size_t\ \{\n\ \ \ \ \ \ \ \ return\ mpmc_queue_available(&globalWorkQueue)\;\n\ \ \ \ \}\n\ \ \ \ #\ Unsafely\ peeks\ at\ the\ queue.\n\ \ \ \ \$cc\ proc\ globalWorkQueueItems\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj\ *ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ size_t\ head\ =\ globalWorkQueue.head\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ head\;\ i\ <\ globalWorkQueue.tail\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ mpmc_queue_cell\ *cell\ =\ &globalWorkQueue.buffer\[i\ &\ globalWorkQueue.buffer_mask\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ *ptr\ =\ cell->data\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ *ptr\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ itemToStringObj(item))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nWish\ the\ web\ server\ handles\ route\ \"/threads\"\ with\ handler\ \{\n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/web.folk does not run} are (
[ m105:0 (s160:0) ]
[ m547:0 (s869:0 s870:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/web.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/web.folk programCode try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ so\ closing\ a\ tab\ doesn't\ crash\ Folk,\ but\n#\ we\ don't\ want\ to\ block/ignore,\ because\ that\ will\ cause\ child\n#\ processes\ to\ also\ block/ignore\ and\ behave\ weirdly.\nsignal\ handle\ SIGPIPE\n\n#\ To\ force\ a\ rebuild:\ rm\ vendor/wslay/Makefile\nif\ \{!\[file\ exists\ vendor/wslay/Makefile\]\}\ \{\n\ \ \ \ puts\ \"web:\ Configuring\ libwslay...\"\n\ \ \ \ exec\ sh\ -c\ \{cd\ vendor/wslay\ &&\ autoreconf\ -i\ &&\ automake\ &&\ autoconf\ &&\ ./configure\}\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"web:\ Building\ libwslay...\"\nexec\ make\ -C\ vendor/wslay\ >@stdout\ 2>@stderr\nputs\ \"web:\ libwslay\ built.\"\n\nsource\ \"lib/ws.tcl\"\n#\ We\ export\ wsLib\ so\ that\ other\ threads\ can\ emit\ messages\ onto\n#\ websockets.\nClaim\ the\ websocket\ library\ is\ \$wsLib\n\nproc\ handleConnect\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ timeout\ 2000\n\ \ \ \ fileevent\ \$chan\ readable\ \[list\ apply\ \{\{chan\ addr\}\ \{\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleRead\ \$chan\ \$addr\n\ \ \ \ \ \ \ \ \}\ on\ signal\ \{sig\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$sig\ on\ \$chan\ \$addr\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$chan\ \$addr\]\n\}\n\nproc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\nproc\ readFile\ \{filename\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\;\ close\ \$fd\;\ return\ \$response\n\}\n\nproc\ headerGet\ \{headers\ name\ args\}\ \{\n\ \ \ \ foreach\ \{k\ v\}\ \$headers\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ -nocase\ \$k\ \$name\]\}\ \{\ return\ \$v\ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[llength\ \$args\]\ >\ 0\}\ \{\ return\ \[lindex\ \$args\ 0\]\ \}\n\ \ \ \ error\ \"missing\ HTTP\ header\ \$name\"\n\}\n\nproc\ handlePage\ \{path\ httpStatusVar\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ switch\ -exact\ --\ \$path\ \{\n\ \ \ \ \ \ \ \ \"/favicon.ico\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"image/x-icon\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/favicon.ico\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/style.css\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/css\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/style.css\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/lib/folk.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"lib/folk.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/vendor/idiomorph.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"vendor/idiomorph.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ \$httpStatusVar\ httpStatus\n\ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 404\ Not\ Found\"\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <b>\$path</b>\ Not\ found.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ parseQueryString\ \{queryString\}\ \{\n\ \ \ \ set\ QUERY\ \[dict\ create\]\n\ \ \ \ if\ \{\$queryString\ eq\ \"\"\}\ \{\ return\ \$QUERY\ \}\n\n\ \ \ \ set\ queryString\ \[string\ range\ \$queryString\ 1\ end\]\n\ \ \ \ foreach\ pair\ \[split\ \$queryString\ &\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^=\]*)=(.*)\$\}\ \$pair\ ->\ key\ value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ URL\ decode\ key\ and\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$key\ \{\ \}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$key\ \{\[format\ %c\ 0x\\1\]\}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[subst\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$value\ \{\ \}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$value\ \{\[format\ %c\ 0x\\1\]\}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[subst\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ QUERY\ \$key\ \$value\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$QUERY\n\}\n\nfn\ HtmlWhen\ args\ \{\n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n\}\n\nproc\ handleRead\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ buffering\ none\n\n\ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ set\ firstline\ \$line\n\n\ \ \ \ #\ puts\ \"Http\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%H:%M:%S\"\]):\ \$chan\ \$addr:\ \$line\"\n\ \ \ \ set\ headers\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ \ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{\ break\ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ Http:\ (\$line)\"\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^\\s:\]+)\\s*:\\s*(.+)\}\ \$line\ ->\ k\ v\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ headers\ \$k\ \$v\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ stderr\ \"Http:\ Weird\ line:\ \$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[regexp\ \{GET\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\ &&\ \$path\ ne\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ set\ response\ \{\}\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ForEach!\ /someone/\ wishes\ the\ web\ server\ handles\ route\ /route/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ handler\ \[dict\ get\ \$options\ handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[regexp\ -inline\ ^\$\{route\}(\\\\?.*)?\$\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$vars\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ queryString\ \[lindex\ \$vars\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ QUERY\ \[parseQueryString\ \$queryString\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^html\ \[proc\ html\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ text/html\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^json\ \[proc\ json\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ application/json\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$handler\ 0\]\ eq\ \"applyBlock\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ create\ QUERY\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$vars\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ \$i\ \[lindex\ \$vars\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ handler\ 2\ \[linsert\ \[lindex\ \$handler\ 2\]\ end\ \$env\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[\{*\}\$handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varNames\ \[lseq\ \[llength\ \$vars\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ varNames\ QUERY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[apply\ \[list\ \$varNames\ \$handler\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$vars\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$response\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[handlePage\ \$path\ httpStatus\ contentType\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"\$httpStatus\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$response\ statusAndHeaders\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Response\ not\ generated\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ \{err\ opts\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errorInfo\ \[dict\ get\ \$opts\ -errorinfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ src\ \[lindex\ \$errorInfo\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Web\ error\ in\ \$src\ (\$path):\ \$err\\n\ \ \[errorInfo\ \$err\ \$errorInfo\]\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text-html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>folk:\ 500\ Internal\ Server\ Error</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \$err\]:\n\[htmlEscape\ \[errorInfo\ \$err\ \$errorInfo\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 500\ Internal\ Server\ Error\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ statusAndHeaders\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$response\ body\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[regexp\ \{POST\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\}\ \{\n\ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ set\ contentType\ \"text/plain\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"\$httpStatus\\r\\nConnection:\ close\\r\\nContent-Type:\ \$contentType\\r\\n\\r\\n\"\n\n\ \ \ \ \ \ \ \ set\ body\ \[\$chan\ read\ \[headerGet\ \$headers\ Content-Length\]\]\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ (\$body)\"\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[eval\ \$body\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[info\ exists\ path\]\ &&\ \$path\ eq\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"web:\ Request\ for\ /ws\ (\$headers)\"\n\ \ \ \ \ \ \ \ set\ clientKey\ \[headerGet\ \$headers\ Sec-WebSocket-Key\ \"\"\]\n\ \ \ \ \ \ \ \ if\ \{\$clientKey\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"HTTP/1.1\ 400\ Bad\ Request\\r\\nConnection:\ close\\r\\nContent-Type:\ text/plain\;\ charset=utf-8\\r\\n\\r\\nMissing\ Sec-WebSocket-Key\\r\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ WsConnection\ upgrade\ \$chan\ \$clientKey\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ Retract!\ websocket\ \$chan\ is\ connected\]\n\ \ \ \ \ \ \ \ Assert!\ websocket\ \$chan\ is\ connected\n\n\ \ \ \ \}\ else\ \{\ puts\ \"Closing:\ \$chan\ \$addr\ \$headers\"\;\ close\ \$chan\ \}\n\}\n\nwhile\ true\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[socket\ stream.server\ 4273\]\n\ \ \ \ \ \ \ \ \$f\ listen\ 128\n\ \ \ \ \ \ \ \ \$f\ readable\ \[lambda\ \{\}\ \{f\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ client\ \[\$f\ accept\ addr\]\n\ \ \ \ \ \ \ \ \ \ \ \ handleConnect\ \$client\ \$addr\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ break\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ #\ Handles\ failure\ to\ bind\ to\ :4273.\ We\ try\ again\ in\ a\ second.\n\ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$e\"\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\nvwait\ forever\n\n\}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ puts\ \$::realStderr\ \"WARNING:\ web.folk\ failed\ to\ initialize\;\nthe\ web\ server\ is\ probably\ down\;\ check\ /var/tmp/folk-\[pid\]/\ for\ log\ files.\n(Make\ sure\ libtool\ and\ autoconf-archive\ are\ installed.)\n------------------------------------------\n\[errorInfo\ \$e\]\"\n\ \ \ \ return\ -options\ \$opts\ \$e\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/statements.folk does not ru (
[ m107:0 (s165:0) ]
[ m561:0 (s883:0 s884:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/statements.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/statements.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/quads.folk does not run} ar (
[ m108:0 (s164:0) ]
[ m552:0 (s871:0 s873:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/quads.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/quads.folk programCode {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk does not run (
[ m111:0 (s170:0) ]
[ m571:0 (s894:0 s895:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/keyboards.folk programCode {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk does not ru (
[ m113:0 (s171:0) ]
[ m580:0 (s908:0 s909:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/trie-graph.folk programCode set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ \ \ \ \$cc\ include\ <stdlib.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\ \ \ \ \$cc\ include\ \"trie.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ Db\ Db\;\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ void\ dbLockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ void\ dbUnlockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ Trie*\ dbGetClauseToStatementRef(Db*\ db)\;\n\n#ifdef\ TRACY_ENABLE\n\n#include\ <string.h>\nvoid\ *tmalloc(size_t\ sz)\ \{\n\ \ \ \ void\ *ptr\ =\ malloc(sz)\;\n\ \ \ \ TracyCAllocS(ptr,\ sz,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nvoid\ *tcalloc(size_t\ s1,\ size_t\ s2)\ \{\n\ \ \ \ void\ *ptr\ =\ calloc(s1,\ s2)\;\n\ \ \ \ TracyCAllocS(ptr,\ s1\ *\ s2,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nchar\ *tstrdup(const\ char\ *s0)\ \{\n\ \ \ \ int\ sz\ =\ strlen(s0)\ +\ 1\;\n\ \ \ \ char\ *s\ =\ tmalloc(sz)\;\n\ \ \ \ memcpy(s,\ s0,\ sz)\;\n\ \ \ \ return\ s\;\n\}\nvoid\ tfree(void\ *ptr)\ \{\n\ \ \ \ TracyCFreeS(ptr,\ 4)\;\n\ \ \ \ free(ptr)\;\n\}\n\n#else\n\n#define\ tmalloc\ malloc\n#define\ tcalloc\ calloc\n#define\ tstrdup\ strdup\n#define\ tfree\ free\n\n#endif\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ tclify\ \{Trie*\ trie\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ objc\ =\ 3\ +\ trie->branchesCount\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ objv\[objc\]\;\n\ \ \ \ \ \ \ \ objv\[0\]\ =\ Jim_ObjPrintf(\"x%\"\ PRIxPTR,\ (uintptr_t)\ trie)\;\n\ \ \ \ \ \ \ \ objv\[1\]\ =\ trie->key\ ?\ Jim_ObjPrintf(\"%s\",\ trie->key)\ :\ Jim_ObjPrintf(\"ROOT\")\;\n\ \ \ \ \ \ \ \ objv\[2\]\ =\ trie->value\ ?\ Jim_ObjPrintf(\"%\"PRIu64,\ trie->value)\ :\ Jim_ObjPrintf(\"NULL\")\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ trie->branchesCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ HACK:\ const\ isn't\ supported\ yet,\ so\ have\ to\ cast.\n\ \ \ \ \ \ \ \ \ \ \ \ objv\[3+i\]\ =\ trie->branches\[i\]\ ?\ tclify((Trie\ *)trie->branches\[i\])\ :\ Jim_NewStringObj(interp,\ \"\",\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ objv,\ objc)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ dbTrieTclify\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ dbLockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Trie*\ trie\ =\ dbGetClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ tclify(trie)\;\n\ \ \ \ \ \ \ \ dbUnlockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ jimObjToClause\ \{Jim_Obj*\ clauseObj\}\ Clause*\ \{\n\ \ \ \ \ \ \ \ int\ nTerms\ =\ Jim_ListLength(interp,\ clauseObj)\;\n\ \ \ \ \ \ \ \ Clause*\ clause\ =\ clauseNew(nTerms)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ termObj\ =\ Jim_ListGetIndex(interp,\ clauseObj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ termLen\;\n\ \ \ \ \ \ \ \ \ \ \ \ const\ char*\ termStr\ =\ Jim_GetString(termObj,\ &termLen)\;\n\ \ \ \ \ \ \ \ \ \ \ \ clause->terms\[i\]\ =\ termNew(termStr,\ termLen)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ clause\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ clauseToJimObj\ \{Clause*\ clause\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ termObjs\[clause->nTerms\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ clause->nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ termObjs\[i\]\ =\ Jim_NewStringObj(interp,\ termPtr(clause->terms\[i\]),\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ termLen(clause->terms\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ termObjs,\ clause->nTerms)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ new\ \{\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieNew()\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ add\ \{Trie*\ trie\ Jim_Obj*\ patternObj\ uint64_t\ value\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieAdd(trie,\ tmalloc,\ tfree,\ pattern,\ value)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ lookup\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\ =\ trieLookup(trie,\ pattern,\ results,\ 50)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultObjs\[resultCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ resultObjs\[i\]\ =\ Jim_NewIntObj(interp,\ results\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ resultObjs,\ resultCount)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ remove_\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\;\n\ \ \ \ \ \ \ \ trie\ =\ (Trie\ *)trieRemove(trie,\ tmalloc,\ tfree,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pattern,\ results,\ 50,\ &resultCount)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\ \ \ \ \ \ \ \ return\ trie\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nset\ trieDotify\ \{\{trieLib\ tclifiedTrie\}\ \{\n\ \ \ \ local\ proc\ idify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ generate\ id-able\ word\ by\ eliminating\ all\ non-alphanumeric\n\ \ \ \ \ \ \ \ regsub\ -all\ \{\\W+\}\ \$word\ \"_\"\n\ \ \ \ \}\n\ \ \ \ local\ proc\ labelify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ shorten\ the\ longest\ lines\n\ \ \ \ \ \ \ \ set\ word\ \[join\ \[lmap\ line\ \[split\ \$word\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$word\]\n\ \ \ \ \}\n\ \ \ \ local\ proc\ subdot\ \{subtrie\}\ \{\n\ \ \ \ \ \ \ \ set\ branches\ \[lassign\ \$subtrie\ ptr\ key\ id\]\n\n\ \ \ \ \ \ \ \ set\ dot\ \[list\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ \\\[label=\\\"\[labelify\ \$key\]\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ branch\ \$branches\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$branch\ eq\ \{\}\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ branchptr\ \[lindex\ \$branch\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ ->\ \$branchptr\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \[subdot\ \$branch\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[join\ \$dot\ \"\\n\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[subdot\ \$tclifiedTrie\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWish\ the\ web\ server\ handles\ route\ \{/trie-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/page.folk does not run} are (
[ m114:0 (s173:0) ]
[ m582:0 (s910:0 s912:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/page.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/page.folk programCode Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk does not r (
[ m118:0 (s179:0) ]
[ m594:0 (s925:0 s926:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/atomicallys.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/new.folk does not run} are (
[ m120:0 (s182:0) ]
[ m600:0 (s934:0 s935:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/new.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/new.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ handler\ \{\n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/log.folk does not run} are (
[ m121:0 (s185:0) ]
[ m608:0 (s945:0 s946:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/log.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/log.folk programCode {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk does not (
[ m122:0 (s186:0) ]
[ m616:0 (s956:0 s957:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/camera-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk does no (
[ m125:0 (s191:0) ]
[ m622:0 (s965:0 s966:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/apriltag-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/report.folk does not run} a (
[ m127:0 (s193:0) ]
[ m628:0 (s974:0 s975:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/report.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/report.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk does (
[ m128:0 (s194:0) ]
[ m634:0 (s983:0 s984:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/printed-programs.folk programCode {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/index.folk does not run} ar (
[ m131:0 (s199:0) ]
[ m642:0 (s994:0 s995:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/index.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/index.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/web/camera.folk does not run} a (
[ m132:0 (s200:0) ]
[ m650:0 (s1005:0 s1006:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/camera.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/web/camera.folk programCode {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.fol (
[ m134:0 (s203:0) ]
[ m658:0 (s1016:0 s1017:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/calibration-board.folk programCode #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ -\ paper\ edge\ to\ top\ margin\n#\n#\ -\ paper\ edge\ to\ bottom\ margin\n#\n#\ -\ paper\ edge\ to\ left\ margin\n#\n#\ -\ tag\ inner\ width,\ to\ account\ for\ scaling.\ (We\ also\ want\ this\ tag\n#\ \ \ inner\ width\ to\ be\ exactly\ the\ same\ as\ the\ tag\ inner\ width\ that\ we\n#\ \ \ use\ on\ every\ printed\ program,\ so\ that\ if\ the\ user\ measures\ the\ tag\n#\ \ \ wrong,\ it\ still\ looks\ OK\ on\ the\ average\ program.)\n#\n#\ Then\ we\ can\ correct\ for\ these\ factors\ in\ all\ future\ prints,\ so\ we\n#\ can\ print\ mm-accurate.\n\n#\ These\ values\ are\ all\ in\ points\ (1/72\ of\ an\ inch).\nset\ marginTop\ 48\;\ set\ marginLeft\ 48\n\nset\ measureTop\ \[/\ \$marginTop\ 2\]\;\ set\ measureLeft\ \[/\ \$marginLeft\ 2\]\nset\ tagInnerSideLength\ 70\n\nWhen\ the\ calibration\ measurements\ are\ /measurements/\ \{\n\ \ \ \ set\ m_tag\ \[string\ trimright\ \[dict\ get\ \$measurements\ tagSideLength\]\ mm\]\n\ \ \ \ set\ m_left\ \[string\ trimright\ \[dict\ get\ \$measurements\ left\]\ mm\]\n\ \ \ \ set\ m_bottom\ \[string\ trimright\ \[dict\ get\ \$measurements\ bottom\]\ mm\]\n\n\ \ \ \ #\ Derive\ a\ PostScript\ CTM\ that\ maps\ calibrated\ space\ (origin\ at\n\ \ \ \ #\ paper\ bottom-left,\ 1\ unit\ =\ 1\ physical\ point\ =\ 25.4/72\ mm)\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coordinate\ space.\n\ \ \ \ #\n\ \ \ \ #\ The\ calibration\ board\ was\ printed\ unmediated,\ so\ its\ PS\ coords\n\ \ \ \ #\ are\ the\ printer's\ raw\ coords.\ \ The\ measurement\ lines\ were\ drawn\n\ \ \ \ #\ at\ PS\ positions\ measureLeft\ and\ measureTop\;\ the\ tag\ inner\ side\n\ \ \ \ #\ was\ tagInnerSideLength\ PS\ points.\ \ From\ the\ physical\ measurements\n\ \ \ \ #\ (in\ mm)\ we\ can\ recover\ the\ printer's\ scale\ and\ origin\ offset.\n\ \ \ \ set\ scale\ \[expr\ \{25.4\ *\ \$tagInnerSideLength\ /\ (72.0\ *\ \$m_tag)\}\]\n\ \ \ \ set\ tx\ \[expr\ \{\$measureLeft\ -\ \$m_left\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\ \ \ \ set\ ty\ \[expr\ \{\$measureTop\ -\ \$m_bottom\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\n\ \ \ \ Claim\ the\ calibrated\ print\ scale\ is\ \$scale\n\ \ \ \ Claim\ the\ calibrated\ print\ translation\ is\ \[list\ \$tx\ \$ty\]\n\}\n\nWhen\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ \{\n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk (
[ m137:0 (s207:0) ]
[ m664:0 (s1026:0 s1027:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/load-calibration.folk programCode When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\}\n\nWhen\ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n\}\n\nWhen\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n\}\n\nWhen\ the\ collected\ results\ for\ \{/somebody/\ claims\ the\ default\ program\ geometry\ is\ /geom/\}\ are\ /results/\ \{\n\ \ \ \ set\ defaultGeometry\ \{tagSize\ 30mm\ top\ 28mm\ right\ 28mm\ left\ 157mm\ bottom\ 80mm\}\n\ \ \ \ set\ shouldClaim\ false\n\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\ ||\n\ \ \ \ \ \ \ \ \[llength\ \$results\]\ ==\ 1\ &&\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\ ==\ \$defaultGeometry\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeometry\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk d (
[ m138:0 (s209:0) ]
[ m683:0 (s1054:0 s1055:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/calibrate-page.folk programCode When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk does not r (
[ m142:0 (s214:0) ]
[ m689:0 (s1063:0 s1064:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/model.folk programCode #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\nClaim\ the\ calibration\ model\ library\ is\ \[library\ create\ modelLib\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\n\n\ \ \ \ variable\ ROWS\ 5\n\ \ \ \ variable\ COLS\ 4\n\ \ \ \ proc\ rows\ \{\}\ \{\ variable\ ROWS\;\ return\ \$ROWS\ \}\n\ \ \ \ proc\ cols\ \{\}\ \{\ variable\ COLS\;\ return\ \$COLS\ \}\n\ \ \ \ #\ A\ model\ is\ a\ dictionary\ whose\ keys\ are\ tag\ IDs\ and\ where\ each\n\ \ \ \ #\ value\ is\ a\ dictionary\ with\ keys\ `c`\ and\ `p`\ which\ are\ model\n\ \ \ \ #\ points\ (x,\ y).\n\ \ \ \ proc\ unitModel\ \{\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ set\ UNIT_MODEL\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ \ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ \ \ \ \ set\ pad\ \[expr\ \{\$tagSideLength\ /\ 3\}\]\n\ \ \ \ \ \ \ \ for\ \{set\ row\ 0\}\ \{\$row\ <\ \$ROWS\}\ \{incr\ row\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ col\ 0\}\ \{\$col\ <\ \$COLS\}\ \{incr\ col\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[expr\ \{48600\ +\ \$row*\$COLS\ +\ \$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$row\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ outer\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{\$modelX\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{\$modelY\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ inner\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopLeft\ \[list\ \$modelX\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[list\ \$modelX\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c\ \[scale\ 0.5\ \[add\ \$modelTopLeft\ \$modelBottomRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p\ \[list\ \$modelBottomLeft\ \$modelBottomRight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelTopRight\ \$modelTopLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ UNIT_MODEL\ \$id\ \$modelTag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$UNIT_MODEL\n\ \ \ \ \}\n\ \ \ \ #\ Tags\ with\ isPrintedTag\ will\ get\ projected\ to\ PostScript\ points\n\ \ \ \ #\ and\ printed\;\ tags\ with\ isProjectedTag\ will\ get\ projected\ to\n\ \ \ \ #\ Vulkan\ points\ and\ rendered\ on\ projector.\n\n\ \ \ \ #\ Tag\ operations.\n\ \ \ \ #\ ---------------\n\n\ \ \ \ proc\ isCalibrationTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ return\ \$(\$id\ >=\ 48600\ &&\ \$id\ <\ 48600\ +\ \$ROWS*\$COLS)\n\ \ \ \ \}\n\ \ \ \ proc\ isPrintedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ COLS\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{int(\$idx\ /\ \$COLS)\}\]\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$idx\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$row\ %\ 2\ ==\ 0\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 1)\ :\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 0)\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\ \ \ \ proc\ isProjectedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{!\[isPrintedTag\ \$id\]\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ isVersionTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$idx\ %\ 4\ ==\ 1\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\n\ \ \ \ #\ Model\ operations.\n\ \ \ \ #\ -----------------\n\n\ \ \ \ #\ Takes\ a\ model\ object\ (dictionary\ of\ tag\ ID\ =>\ \{p,\ c\})\ and\n\ \ \ \ #\ rotates\ version\ tags\ according\ to\ version.\n\ \ \ \ proc\ updateModelVersion\ \{model\ version\}\ \{\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ version\ tag.\ Rotate\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$model\ \$id\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rotatedCorners\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 4\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ rotatedCorners\ \[lindex\ \$p\ \[expr\ \{(\$i\ +\ \$version)\ %\ 4\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ model\ \$id\ p\ \$rotatedCorners\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$model\n\ \ \ \ \}\n\ \ \ \ proc\ scaleModel\ \{model\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ c\ \[scale\ \$scale\ \[dict\ get\ \$tag\ c\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ p\ \[scale\ \$scale\ \[dict\ get\ \$tag\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ proc\ countProjectedTags\ \{model\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\}\ \{\ incr\ i\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$i\n\ \ \ \ \}\n\n\ \ \ \ #\ Detected\ tag-list\ operations.\n\ \ \ \ #\ -----------------------------\n\ \ \ \ proc\ filterProjectedTagsInDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ return\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Find\ a\ version\ tag\ that\ the\ camera\ saw\ and\ check\ its\ rotation\ to\n\ \ \ \ #\ figure\ out\ the\ model\ version\ that\ we're\ seeing.\n\ \ \ \ proc\ detectVersionFromDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ local\ proc\ getTagAngle\ \{tag\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{atan2(-1\ *\ (\[lindex\ \$p\ 1\ 1\]\ -\ \[lindex\ \$p\ 0\ 1\]),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$p\ 1\ 0\]\ -\ \[lindex\ \$p\ 0\ 0\])\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Find\ any\ version\ tag.\ If\ none\ were\ detected,\ then\ abort\n\ \ \ \ \ \ \ \ #\ and\ wait\ until\ a\ later\ frame.\n\ \ \ \ \ \ \ \ foreach\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isVersionTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagId\ \$tag(id)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagAngle\ \[getTagAngle\ \$tag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ versionTagId\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ #\ Compare\ angle\ to\ angle\ of\ any\ other\ projected\ tag.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$detectedTags\]\ <\ 2\}\ \{\ return\ \{\}\ \}\n\ \ \ \ \ \ \ \ foreach\ detectedTag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$detectedTag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\ &&\ !\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ otherTagAngle\ \[getTagAngle\ \$detectedTag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ otherTagAngle\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ set\ versionAngle\ \[expr\ \{\$versionTagAngle\ -\ \$otherTagAngle\}\]\n\ \ \ \ \ \ \ \ #\ Rotations\ corresponding\ to\ versions\ 0,\ 1,\ 2,\ 3:\n\ \ \ \ \ \ \ \ set\ possibleVersions\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ 1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ 1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ -1\]\n\ \ \ \ \ \ \ \ #\ Which\ of\ the\ possibleVersions\ is\ versionAngle\ closest\ to?\n\ \ \ \ \ \ \ \ return\ \[lindex\ \[lsort-indices\ \[lmap\ \{x\ y\}\ \$possibleVersions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{sqrt((\$x\ -\ cos(\$versionAngle))**2\ +\ (\$y\ -\ sin(\$versionAngle))**2)\}\n\ \ \ \ \ \ \ \ \}\]\]\ 0\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ meanTagsDifference\ \{tags1\ tags2\}\ \{\n\ \ \ \ \ \ \ \ set\ diffsum\ 0.0\n\ \ \ \ \ \ \ \ set\ ndiffs\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$tags1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ cheat\ and\ only\ count\ printed\ tags\ so\ we\ don't\ have\ to\n\ \ \ \ \ \ \ \ \ \ \ \ #\ deal\ with\ versioning.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$tags2\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x1\ y1\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tags2\ \$id\ c\]\ x2\ y2\n\ \ \ \ \ \ \ \ \ \ \ \ set\ diffsum\ \[expr\ \{\$diffsum\ +\ sqrt((\$x1\ -\ \$x2)*(\$x1\ -\ \$x2)\ +\ (\$y1\ -\ \$y2)*(\$y1\ -\ \$y2))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ ndiffs\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$ndiffs\ ==\ 0\}\ \{\ return\ Inf\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$diffsum\ /\ \$ndiffs\}\]\n\ \ \ \ \}\n\}\]\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk does (
[ m143:0 (s217:0) ]
[ m695:0 (s1072:0 s1073:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/draw-model.folk programCode When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ calibration\ model\ /model/\ \\\n\ \ \ \ \ \ \ \ using\ model-to-display\ homography\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ with\ message\ /calibrationMessage/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk does not (
[ m144:0 (s218:0) ]
[ m701:0 (s1081:0 s1082:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/refine.folk programCode #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (or\n#\ \ \ \ \ projector\ calibration,\ equivalently)\ (see\ Zhengyou\ Zhang)\ using\n#\ \ \ \ \ cmpfit.\n#\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk does not run (
[ m148:0 (s224:0) ]
[ m707:0 (s1090:0 s1091:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/enumerate.folk programCode {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
$cc proc enumerateDisplays {} Jim_Obj* {
FOLK_ENSURE(volkInitialize() == VK_SUCCESS);
// Create a minimal Vulkan instance for display enumeration.
VkInstance instance;
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* enabledExtensions[] = {
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#ifdef __APPLE__
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
createInfo.ppEnabledExtensionNames = enabledExtensions;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
if (res == VK_ERROR_EXTENSION_NOT_PRESENT) {
FOLK_ERROR("Unable to enumerate displays (for example, this doesn't work on macOS)");
}
FOLK_ERROR("Failed to create Vulkan instance: %d", res);
}
}
volkLoadInstance(instance);
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
vkDestroyInstance(instance, NULL);
return Jim_NewListObj(interp, NULL, 0);
}
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
Jim_Obj *allDisplaysList = Jim_NewListObj(interp, NULL, 0);
// Enumerate displays for each physical device
for (uint32_t devIdx = 0; devIdx < physicalDeviceCount; devIdx++) {
VkPhysicalDevice physicalDevice = physicalDevices[devIdx];
uint32_t displayCount;
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, NULL);
VkDisplayPropertiesKHR displayProps[displayCount];
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProps);
for (uint32_t i = 0; i < displayCount; i++) {
uint32_t modeCount;
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, NULL);
VkDisplayModePropertiesKHR modeProps[modeCount];
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, modeProps);
Jim_Obj *modesList = Jim_NewListObj(interp, NULL, 0);
for (uint32_t j = 0; j < modeCount; j++) {
Jim_Obj *modeDict = Jim_ObjPrintf("visibleRegion {%u %u} refreshRate %u",
modeProps[j].parameters.visibleRegion.width,
modeProps[j].parameters.visibleRegion.height,
modeProps[j].parameters.refreshRate);
Jim_ListAppendElement(interp, modesList, modeDict);
}
int modesLen;
const char *modesStr = Jim_GetString(modesList, &modesLen);
Jim_Obj *displayDict = Jim_ObjPrintf("name {%s} physicalDimensions {%u %u} "
"physicalResolution {%u %u} modes {%s}",
displayProps[i].displayName ? displayProps[i].displayName : "",
displayProps[i].physicalDimensions.width,
displayProps[i].physicalDimensions.height,
displayProps[i].physicalResolution.width,
displayProps[i].physicalResolution.height,
modesStr);
Jim_ListAppendElement(interp, allDisplaysList, displayDict);
}
}
vkDestroyInstance(instance, NULL);
return allDisplaysList;
}
set displayLib [$cc compile]
if {![catch {exec pkg-config --exists glfw3}]} {
Claim $::thisNode has display glfw with info {name "GLFW (windowed)"}
}
try {
foreach display [$displayLib enumerateDisplays] {
Claim $::thisNode has display $display(name) with info $display
}
} finally {
Claim $::thisNode has had displays enumerated
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk does not (
[ m149:0 (s225:0) ]
[ m713:0 (s1098:0 s1099:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/matlib.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk does n (
[ m150:0 (s227:0) ]
[ m719:0 (s1107:0 s1108:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/calibrate/calibrate.folk programCode #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ calibration\n#\ \ \ \ \ pattern\ PDF,\ have\ the\ user\ measure\ its\ real-world\ dimension,\ run\n#\ \ \ \ \ iterative\ projector-camera\ process\ to\ get\ various\ poses\ of\ the\n#\ \ \ \ \ printed\ tags\ alongside\ projected\ tags,\ do\ linear\ fit\ and\ then\n#\ \ \ \ \ nonlinear\ refinement\ to\ find\ intrinsic\ and\ extrinsic\ parameters\n#\ \ \ \ \ for\ the\ camera\ and\ projector.\n#\n#\ \ \ \ \ Closely\ based\ on\ the\ technique\ in\ Audet\ (2009):\n#\ \ \ \ \ http://www.ok.sc.e.titech.ac.jp/res/PCS/publications/procams2009.pdf\n#\n\npackage\ require\ linalg\n\nforeach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\}\ \{\n\ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\}\n\nHold!\ -key\ \{calibration\ poses\ max\}\ \\\n\ \ \ \ Claim\ the\ calibration\ poses\ max\ is\ 10\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ AprilTag\ detector\ maker\ is\ /makeAprilTagDetector/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ calibrate\ camera\ /camera/\ to\ display\ /display/\ \\\n\ \ \ \ \ \ \ \ \ using\ measurements\ /measurements/\ \{\n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nfn\ processHomography\ \{H\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n\}\n\n\n#\ Uses\ Zhang's\ calibration\ technique\n#\ (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf)\n#\ to\ calibrate\ a\ projector\ or\ camera\ given\ a\ known\ 2D\ planar\ pattern\n#\ and\ multiple\ observed\ poses.\n#\n#\ Returns\ intrinsic\ matrix\ for\ the\ camera/projector,\ which\ explains\n#\ how\ 3D\ real-world\ coordinates\ get\ projected\ to\ 2D\ coordinates\ by\n#\ that\ device.\ (The\ intrinsic\ matrix\ can\ be\ used\ with\ an\ AprilTag\n#\ detector\ to\ get\ real-world\ coordinates\ for\ each\ AprilTag.)\n#\n#\ Arguments:\n#\ \ \ \ \ \ \ \ \ width\ \ width\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ height\ height\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ Hs\ \ \ \ \ a\ list\ of\ N\ homographies\ from\ camera/projector\ image\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ plane\ ->\ model\ plane\ (for\ N\ different\ poses).\nfn\ zhangUnrefinedCalibrate\ \{name\ width\ height\ Hs\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n\}\n\nfn\ setCameraToProjectorExtrinsics\ \{modelLib\ calibrationVar\ calibrationPoses\}\ \{\n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n\}\n\n#\ End-to-end\ calibrates\ a\ camera-projector\ pair.\ calibrationPoses\ is\n#\ a\ list\ of\ N\ pose\ dictionaries.\ Each\ pose\ dictionary\ includes\ `tags`\n#\ from\ a\ camera\ detection,\ `model`\ with\ coordinates\ in\ meters,\n#\ `H_modelToDisplay`.\nfn\ unrefinedCalibrateCameraAndProjector\ \{modelLib\ matLib\ calibrationPoses\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n\}\n\nWhen\ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ &\\\n\ \ \ \ \ the\ calibration\ refiner\ is\ /refineCalibration/\ \{\n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk does not run (
[ m152:0 (s230:0) ]
[ m726:0 (s1119:0 s1120:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/pipelines.folk programCode #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ compilation.\n#\ \ \ \ \ Created\ once\ (not\ per-display).\ Pipelines\ use\ dynamic\ viewport/scissor\n#\ \ \ \ \ so\ they\ work\ across\ displays\ of\ different\ sizes.\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk does not run} are (
[ m155:0 (s235:0) ]
[ m732:0 (s1128:0 s1129:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/gpu.folk programCode {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq "darwin"} {
# We hard-code gpu.folk into thread 0, so we should abort if not
# running that way.
return
}
fn defineVulkanHandleType {cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
}
Claim the GPU Vulkan handle type definer is [fn defineVulkanHandleType]
fn gpuInit {useGlfw} {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
}
if {$::tcl_platform(os) eq "darwin"} {
gpuInit true
return
}
When $::thisNode has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk does not run} (
[ m156:0 (s236:0) ]
[ m739:0 (s1139:0 s1140:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/textures.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk does not run} are (
[ m160:0 (s241:0) ]
[ m746:0 (s1149:0 s1150:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/draw.folk programCode #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ and\n#\ \ \ \ \ numerical\ parameters\ (so\ you\ can\ draw\ images,\ shapes,\ etc.)\n#\ \ \ \ \ Single\ render\ thread\ handles\ all\ displays.\n\nif\ \{\[info\ exists\ this\]\ &&\ \$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ #\ We\ hard-code\ draw.folk\ into\ thread\ 0,\ so\ we\ should\ abort\ if\ not\n\ \ \ \ #\ running\ that\ way.\n\ \ \ \ return\n\}\n\nWhen\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ compiler\ library\ is\ /pipelineCompilerLib/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk does not ru (
[ m162:0 (s247:0) ]
[ m752:0 (s1158:0 s1159:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/toy-shader.folk programCode #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <openssl/sha.h>\n\$cc\ proc\ sha1\ \{char*\ d\}\ Jim_Obj*\ \{\n\ \ \ \ unsigned\ char\ md\[20\]\;\n\ \ \ \ SHA1((unsigned\ char\ *)d,\ strlen(d),\ md)\;\n\ \ \ \ return\ Jim_NewStringObj(interp,\ (char\ *)md,\ 20)\;\n\}\n\$cc\ endcflags\ -lssl\ -lcrypto\nset\ sha1Lib\ \[\$cc\ compile\]\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ \{\n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk does not run} (
[ m164:0 (s248:0) ]
[ m760:0 (s1169:0 s1170:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/canvases.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk does not run} are (
[ m165:0 (s249:0) ]
[ m766:0 (s1178:0 s1179:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/vma.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run} (
[ m166:0 (s252:0) ]
[ m851:0 (s1309:0 s1310:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/gpu/gpu-fns.folk programCode {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
Wish the GPU compiles function "wedge2d" {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
# See https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/
Wish the GPU compiles function "invBilinear" {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/shapes/region.folk does not run (
[ m169:0 (s255:0) ]
[ m857:0 (s1320:0 s1321:0) ]
)when the collected results for {/any/ wishes program builtin-programs/shapes/region.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/shapes/region.folk programCode #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ used\ to\ create\ sensitive\ areas\ other\ pages\ can\ collect.\nWhen\ /someone/\ wishes\ /p/\ adds\ region\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ region\ /r/\ has\ highlight\ /highlighted/\ with\ /...options/\ \{\n\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\n\ \ if\ \{\$highlighted\}\ \{\n\ \ \ \ set\ verts\ \[region\ vertices\ \$r\]\n\ \ \ \ set\ edges\ \[region\ edges\ \$r\]\n\ \ \ \ lappend\ verts\ \[lindex\ \$verts\ 0\]\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$verts\ color\ \$color\ width\ \$thickness\ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/display/arc.folk does not run} (
[ m170:0 (s258:0) ]
[ m863:0 (s1331:0 s1332:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display/arc.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/display/arc.folk programCode #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n#\ \ \ \ \ Wish\ to\ draw\ an\ arc\ with\ x\ \$x\ y\ \$y\ start\ 0\ arclen\ 1\ thickness\ 3\ radius\ 100\ color\ green\n#\ \ \ \}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"arc\"\ \{\{vec2\ center\ float\ start\ float\ arclen\ float\ radius\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\ \ \ \ \ \ \ \ \ center\ +\ r\n\ \ \ \ )\;\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\}\ \{\n\ \ \ \ #define\ M_TWO_PI\ 6.283185307179586\n\ \ \ \ start\ =\ clamp(start,\ 0,\ M_TWO_PI)\;\n\ \ \ \ arclen\ =\ clamp(arclen,\ 0,\ M_TWO_PI)\;\n\n\ \ \ \ float\ dist\ =\ length(gl_FragCoord.xy\ -\ center)\ -\ radius\;\n\ \ \ \ float\ angle\ =\ atan(-(gl_FragCoord.y\ -\ center.y),\ gl_FragCoord.x\ -\ center.x)\;\n\n\ \ \ \ //\ Shift\ angle\ from\ \[-pi,\ pi)\ to\ \[0,\ 2*pi\]\n\ \ \ \ angle\ =\ (angle\ <\ 0)\ ?\ (angle\ +\ M_TWO_PI)\ :\ angle\;\n\ \ \ \ float\ end\ =\ start\ +\ arclen\;\n\n\ \ \ \ return\ ((dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((end\ <\ M_TWO_PI\ &&\ angle\ >\ start\ &&\ angle\ <\ end)\ ||\ \n\ \ \ \ \ \ \ \ \ \ \ \ (end\ >=\ M_TWO_PI\ &&\ (angle\ >\ start\ ||\ angle\ <\ end-M_TWO_PI))))\ ?\ color\ :\ vec4(0,\ 0,\ 0,\ 0)\;\n\n\}\}\n\nWhen\ /someone/\ wishes\ to\ draw\ an\ arc\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/display/curve.folk does not run (
[ m173:0 (s263:0) ]
[ m869:0 (s1341:0 s1342:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display/curve.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/display/curve.folk programCode \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ compiles\ function\ \"bboxBezier\"\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\}\ vec4\ \{\n\ \ \ \ //\ Exact\ BBox\ to\ a\ quadratic\ bezier\n\ \ \ \ //\ extremes\n\ \ \ \ vec2\ mi\ =\ min(p0,p3)\;\n\ \ \ \ vec2\ ma\ =\ max(p0,p3)\;\n\n\ \ \ \ vec2\ k0\ =\ -1.0*p0\ +\ 1.0*p1\;\n\ \ \ \ vec2\ k1\ =\ \ 1.0*p0\ -\ 2.0*p1\ +\ 1.0*p2\;\n\ \ \ \ vec2\ k2\ =\ -1.0*p0\ +\ 3.0*p1\ -\ 3.0*p2\ +\ 1.0*p3\;\n\n\ \ \ \ vec2\ h\ =\ k1*k1\ -\ k0*k2\;\n\n\ \ \ \ if(\ h.x>0.0\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.x\ =\ sqrt(h.x)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.x\ -\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.x/(-k1.x-h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.x\ +\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ t\ =\ k0.x/(-k1.x+h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if(\ h.y>0.0)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.y\ =\ sqrt(h.y)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.y\ -\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.y/(-k1.y-h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.y\ +\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ t\ =\ k0.y/(-k1.y+h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \n\ \ \ \ return\ vec4(\ mi,\ ma\ )\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ sdSegmentSq\ \{\{vec2\ p\ vec2\ a\ vec2\ b\}\ float\ \{\n\ \ \ \ vec2\ pa\ =\ p-a,\ ba\ =\ b-a\;\n\ \ \ \ float\ h\ =\ clamp(\ dot(pa,ba)/dot(ba,ba),\ 0.0,\ 1.0\ )\;\n\ \ \ \ vec2\ d\ =\ pa\ -\ ba*h\;\n\ \ \ \ return\ dot(d,\ d)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ udBezier\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ vec2\ pos\}\ vec2\ \{\n\ \ \ \ const\ int\ kNum\ =\ 50\;\n\ \ \ \ vec2\ res\ =\ vec2(1e10,0.0)\;\n\ \ \ \ vec2\ a\ =\ p0\;\n\ \ \ \ for(\ int\ i=1\;\ i<kNum\;\ i++\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ float\ t\ =\ float(i)/float(kNum-1)\;\n\ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ vec2\ b\ =\ p0*s*s*s\ +\ p1*3.0*s*s*t\ +\ p2*3.0*s*t*t\ +\ p3*t*t*t\;\n\ \ \ \ \ \ \ \ float\ d\ =\ sdSegmentSq(\ pos,\ a,\ b\ )\;\n\ \ \ \ \ \ \ \ if(\ d<res.x\ )\ res\ =\ vec2(d,t)\;\n\ \ \ \ \ \ \ \ a\ =\ b\;\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ vec2(sqrt(res.x),res.y)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"curve\"\ \{\n\ \ \{\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ //\ Need\ to\ calculate\ the\ bounds\ of\ the\ curve\n\ \ \ \ vec2\ from\ =\ min(min(p0,p1),min(p2,p3))\;\n\ \ \ \ vec2\ to\ =\ max(max(p0,p1),max(p2,p3))\;\n\ \ \ \ \n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ min(from,\ to)\ -\ thickness,\n\ \ \ \ \ \ vec2(max(from.x,\ to.x)\ +\ thickness,\ min(from.y,\ to.y)\ -\ thickness),\n\ \ \ \ \ \ vec2(min(from.x,\ to.x)\ -\ thickness,\ max(from.y,\ to.y)\ +\ thickness),\n\ \ \ \ \ \ max(from,\ to)\ +\ thickness\n\ \ \ \ )\;\n\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\ \ \}\ \{fn\ sdSegmentSq\ fn\ udBezier\}\ \{\n\ \ \ \ vec2\ p\ =\ gl_FragCoord.xy\;\n\ \ \ \ float\ px\ =\ 2.0\;\ //\ sharpness\n\ \ \ \ float\ t\ =\ thickness\;\n\ \ \ \ float\ be\ =\ udBezier(\ p0,\ p1,\ p2,\ p3,\ p\ ).x\;\n\n\ \ \ \ float\ d\ =\ be\;\n\n\ \ \ \ vec4\ col\ =\ mix(\ vec4(0.0),\ color,\ 1.0-smoothstep(t,\ t\ +\ px*1.5,\ d)\ )\;\n\n\ \ \ \ //\ control\ points\n\ \ \ \ //d\ =\ length(p0-p)\;\ col\ =\ mix(\ col,\ vec4(1.0,\ 0.,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p1-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 1.0,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p2-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 0.,\ 1.0,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p3-p)\;\ col\ =\ mix(\ col,\ vec4(1.0),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\n\ \ \ \ return\ col\;\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ curve\ with\ /...options/\ \{\n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk does not (
[ m174:0 (s264:0) ]
[ m875:0 (s1354:0 s1355:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/recognition/trocr.folk programCode When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ TrOCR\ text\ recognizer\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ TrOCR\ text\ recognizer\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ transformers\ --with\ pillow\ --with\ torch\ --with\ protobuf\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ from\ transformers\ import\ TrOCRProcessor,\ VisionEncoderDecoderModel\n\ \ \ \ \ \ \ \ import\ os\n\ \ \ \ \ \ \ \ import\ sys\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ #\ Determine\ device\ (prefer\ CUDA\ >\ MPS\ >\ CPU)\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ #\ Load\ TrOCR\ model\n\ \ \ \ \ \ \ \ TROCR_PATH\ =\ os.path.expanduser(\"~/folk-data/trocr\")\n\ \ \ \ \ \ \ \ try:\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ disk.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ except\ Exception:\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Model\ not\ saved\;\ loading\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ processor.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ model.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ model.to(device)\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ ocrImage\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ start_time\ =\ time.time()\n\n\ \ \ \ \ \ \ \ #\ Run\ TrOCR\ on\ the\ entire\ image\n\ \ \ \ \ \ \ \ with\ torch.no_grad():\n\ \ \ \ \ \ \ \ \ \ \ \ pixel_values\ =\ processor(image,\ return_tensors=\"pt\").pixel_values.to(device)\n\ \ \ \ \ \ \ \ \ \ \ \ generated_ids\ =\ model.generate(pixel_values)\n\ \ \ \ \ \ \ \ \ \ \ \ text\ =\ processor.batch_decode(generated_ids,\ skip_special_tokens=True)\[0\]\n\n\ \ \ \ \ \ \ \ elapsed\ =\ time.time()\ -\ start_time\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Result:\ \{text\}\ (\{elapsed:.3f\}s)\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ return\ text\n\ \ \ \ \}\n\n\ \ \ \ fn\ TrOCR\ \{im\}\ \{\ return\ \[\$py\ ocrImage\ \$im\]\ \}\n\ \ \ \ Claim\ the\ TrOCR\ text\ recognizer\ is\ \[fn\ TrOCR\]\n\}\n\n} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk does not (
[ m177:0 (s269:0) ]
[ m881:0 (s1364:0 s1365:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/recognition/sam2.folk programCode When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ SAM2\ segmenter\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ SAM2\ segmenter\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n\}\n\n} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk does not (
[ m178:0 (s270:0) ]
[ m887:0 (s1374:0 s1375:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/recognition/craft.folk programCode When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ CRAFT\ text\ detector\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ CRAFT\ text\ detector\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ \"git+https://github.com/osnr/craft-text-detector.git\"\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ from\ craft_text_detector\ import\ Craft\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ craft\ =\ Craft(output_dir=None,\ crop_type=\"box\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ link_threshold=0.1,\ device=device)\n\ \ \ \ \}\n\ \ \ \ \$py\ def\ detectTextBoxes\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image)\n\n\ \ \ \ \ \ \ \ start_craft\ =\ time.time()\n\ \ \ \ \ \ \ \ result\ =\ craft.detect_text(image_np)\n\ \ \ \ \ \ \ \ boxes\ =\ result\[\"boxes\"\]\n\ \ \ \ \ \ \ \ craft_time\ =\ time.time()\ -\ start_craft\n\n\ \ \ \ \ \ \ \ print(f\"craft:\ Detected\ \{len(boxes)\}\ text\ boxes\ (\{craft_time:.3f\}s)\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ return\ boxes.tolist()\ if\ hasattr(boxes,\ 'tolist')\ else\ boxes\n\ \ \ \ \}\n\n\ \ \ \ fn\ CRAFT\ \{im\}\ \{\ return\ \[\$py\ detectTextBoxes\ \$im\]\ \}\n\ \ \ \ Claim\ the\ CRAFT\ text\ detector\ is\ \[fn\ CRAFT\]\n\}\n\n} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk does (
[ m180:0 (s273:0) ]
[ m893:0 (s1384:0 s1385:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/recognition/contours.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ cflags\ -I.\n\ \ \ \ \$cc\ include\ \"vendor/CContour.c\"\n\n\ \ \ \ #\ Binarizes\ the\ first\ channel\ of\ `im`\ at\ `threshold`\ and\ returns\n\ \ \ \ #\ the\ contours\ as\ a\ Tcl\ list.\ Each\ contour\ is\ itself\ a\ Tcl\ list\ of\n\ \ \ \ #\ \{x\ y\}\ pairs.\ If\ epsilon\ >\ 0,\ each\ contour\ is\ simplified\ with\n\ \ \ \ #\ Ramer-Douglas-Peucker.\n\ \ \ \ #\n\ \ \ \ #\ Contours\ are\ scaled\ by\ `scaleX`\ and\ `scaleY`\ so\ that\ they\ can\ be\n\ \ \ \ #\ returned\ in\ real-world\ meters\ (instead\ of\ image-pixel\ space).\n\ \ \ \ #\n\ \ \ \ #\ Discards\ any\ contours\ that\ are\ not\ at\ least\ minLength\ long\n\ \ \ \ #\ (unless\ minLength\ is\ very\ small).\n\ \ \ \ \$cc\ proc\ findImageContours\ \{Image\ im\ int\ threshold\ double\ epsilon\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ scaleX\ double\ scaleY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ minLength\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ w\ =\ (int)im.width\;\n\ \ \ \ \ \ \ \ int\ h\ =\ (int)im.height\;\n\ \ \ \ \ \ \ \ if\ (w\ <\ 3\ ||\ h\ <\ 3)\ return\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ int\ *F\ =\ malloc(sizeof(int)\ *\ (size_t)w\ *\ (size_t)h)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ h\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ *row\ =\ im.data\ +\ (size_t)y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ *Frow\ =\ F\ +\ (size_t)y\ *\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ w\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Frow\[x\]\ =\ (row\[x\ *\ im.components\]\ >\ threshold)\ ?\ 1\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Contour\ *contours\ =\ findContours(F,\ w,\ h)\;\n\ \ \ \ \ \ \ \ free(F)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj\ *outer\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (ptrdiff_t\ c\ =\ 0\;\ c\ <\ arrlen(contours)\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Point\ *pts\ =\ (epsilon\ >\ 0)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ?\ approxPolyDP(contours\[c\].points,\ (float)epsilon)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :\ contours\[c\].points\;\n\ \ \ \ \ \ \ \ \ \ \ \ ptrdiff_t\ n\ =\ arrlen(pts)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (minLength\ >\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ total\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 1\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ (pts\[k\].x\ -\ pts\[k-1\].x)\ *\ scaleX\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ (pts\[k\].y\ -\ pts\[k-1\].y)\ *\ scaleY\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (total\ <\ minLength)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ %g\ prints\ up\ to\ ~13\ chars\ per\ double\;\ round\ up\ to\ give\ headroom.\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ cap\ =\ (size_t)n\ *\ 40\ +\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ char\ *buf\ =\ malloc(cap)\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ off\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 0\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ off\ +=\ snprintf(buf\ +\ off,\ cap\ -\ off,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\ ==\ 0\ ?\ \"\{%g\ %g\}\"\ :\ \"\ \{%g\ %g\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pts\[k\].x\ *\ scaleX,\ pts\[k\].y\ *\ scaleY)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Jim_NewStringObjNoAlloc\ takes\ ownership\ of\ buf.\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ outer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObjNoAlloc(interp,\ buf,\ (int)off))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ freeContours(contours)\;\n\ \ \ \ \ \ \ \ return\ outer\;\n\ \ \ \ \}\n\n\ \ \ \ set\ contourLib\ \[\$cc\ compile\]\n\ \ \ \ Claim\ the\ contour\ library\ is\ \$contourLib\n\}\n\nWhen\ /someone/\ wishes\ /p/\ has\ contours\ \{\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ _\ \{\}\n\}\nWhen\ the\ contour\ library\ is\ /contourLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ contours\ with\ /...opts/\ \{\n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk does not (
[ m184:0 (s278:0) ]
[ m843:0 (s1298:0 s1299:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/saving/save-holds.folk programCode set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ \"jim.h\"\n\n\$cc\ code\ \{\n\n/*\ Generic\ string\ hash\ function\ from\ jim.c\ */\nstatic\ unsigned\ int\ cacheGenHashFunction(const\ unsigned\ char\ *string,\ int\ length)\ \{\n\ \ \ \ unsigned\ result\ =\ 0\;\n\ \ \ \ string\ +=\ length\;\n\ \ \ \ while\ (length--)\ \{\n\ \ \ \ \ \ \ \ result\ +=\ (result\ <<\ 3)\ +\ (unsigned\ char)(*--string)\;\n\ \ \ \ \}\n\ \ \ \ return\ result\;\n\}\nstatic\ unsigned\ int\ holdHTHashFunction(const\ void\ *key)\ \{\n\ \ \ \ return\ cacheGenHashFunction(key,\ strlen(key))\;\n\}\nstatic\ void\ *holdHTKeyDup(void\ *privdata,\ const\ void\ *key)\ \{\n\ \ \ \ return\ strdup(key)\;\n\}\nstatic\ void\ *holdHTValDup(void\ *privdata,\ const\ void\ *val)\ \{\n\ \ \ \ return\ strdup(val)\;\n\}\nstatic\ int\ holdHTKeyCompare(void\ *privdata,\ const\ void\ *key1,\ const\ void\ *key2)\ \{\n\ \ \ \ return\ strcmp(key1,\ key2)\ ==\ 0\;\n\}\nstatic\ void\ holdHTKeyDestructor(void\ *privdata,\ void\ *key)\ \{\n\ \ \ \ free(key)\;\n\}\nstatic\ void\ holdHTValDestructor(void\ *privdata,\ void\ *val)\ \{\n\ \ \ \ free(val)\;\n\}\n\nstatic\ const\ Jim_HashTableType\ holdHashTableType\ =\ \{\n\ \ \ \ .hashFunction\ =\ holdHTHashFunction,\n\ \ \ \ .keyDup\ =\ holdHTKeyDup,\n\ \ \ \ .valDup\ =\ holdHTValDup,\n\ \ \ \ .keyCompare\ =\ holdHTKeyCompare,\n\ \ \ \ .keyDestructor\ =\ holdHTKeyDestructor,\n\ \ \ \ .valDestructor\ =\ holdHTValDestructor\n\}\;\n\n//\ key\ =\ value\ of\ -on\ passed\ to\ Hold!,\n//\ val\ =\ string\ that\ can\ be\ converted\ to\ a\ jim\ dict,\ with\n//\ that\ dict\ having\ its\ key\ =\ the\ value\ passed\ to\ -key\n//\ and\ its\ value\ =\ its\ corresponding\ held\ statement\nstatic\ Jim_HashTable\ holds\;\nstatic\ int\ areHoldsInitialized\ =\ 0\;\n\nstatic\ pthread_mutex_t\ holdMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ if\ (!areHoldsInitialized)\ \{\n\ \ \ \ \ \ \ \ areHoldsInitialized\ =\ 1\;\n\ \ \ \ \ \ \ \ Jim_InitHashTable(&holds,\ &holdHashTableType,\ interp)\;\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n\$cc\ proc\ loadHolds\ \{char*\ canonicalName\ char*\ holdStr\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonicalName,\ (void\ *)holdStr)\;\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n#\ canonical,\ tclEscaped,\ and\ filename\ all\ have\ to\ do\ with\ the\ value\ from\ -on\ in\ Hold!\n\$cc\ proc\ saveHold\ \{char*\ canonical\ Jim_Obj*\ tclEscaped\ char*\ filename\ Jim_Obj*\ key\ Jim_Obj*\ clause\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ assert(areHoldsInitialized)\;\n\n\ \ \ \ Jim_Obj*\ holdDict\ =\ NULL\;\n\n\ \ \ \ Jim_HashEntry*\ he\ =\ Jim_FindHashEntry(&holds,\ canonical)\;\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ //\ this\ is\ this\ files'\ first\ hold\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewStringObj(interp,\ (char\ *)Jim_GetHashEntryVal(he),\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ empty\ clause,\ e.g.\ removal\n\ \ \ \ if\ (Jim_Length(clause)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ NULL)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ clause)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonical,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_SetHashVal(&holds,\ he,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\n\ \ \ \ //\ grab\ entries\ from\ dict\n\ \ \ \ int\ dictLen\ =\ 0\;\n\ \ \ \ Jim_Obj**\ dictValues\ =\ Jim_DictPairs(interp,\ holdDict,\ &dictLen)\;\n\n\ \ \ \ if\ (dictLen\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ //\ write\ changes\n\ \ \ \ \ \ \ \ FILE*\ file\ =\ fopen(filename,\ \"w+b\")\;\n\ \ \ \ \ \ \ \ assert(file\ !=\ NULL)\;\n\n\ \ \ \ \ \ \ \ //\ write\ the\ filename\ in\ tcl\ form\ at\ the\ top\ of\ the\ file\n\ \ \ \ \ \ \ \ fwrite(Jim_String(tclEscaped),\ 1,\ Jim_Length(tclEscaped),\ file)\;\n\ \ \ \ \ \ \ \ fwrite(\"\\n\\n\",\ 1,\ 2,\ file)\;\n\n\ \ \ \ \ \ \ \ //\ write\ all\ hash\ entries,\ with\ one\ entry\ per\ line\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ dictLen\;\ i\ +=\ 2)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ pair\[\]\ =\ \{\ dictValues\[i\],\ dictValues\[i\ +\ 1\]\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ tmpListObj\ =\ Jim_NewListObj(interp,\ pair,\ 2)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(Jim_String(tmpListObj),\ 1,\ Jim_Length(tmpListObj),\ file)\;\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(\"\\n\",\ 1,\ 1,\ file)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_FreeNewObj(interp,\ tmpListObj)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ fclose(file)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ //\ the\ dict\ is\ empty,\ so\ we\ should\ delete\ its\ hold\ file\ if\ it\ exists\n\ \ \ \ \ \ \ \ remove(filename)\;\ //\ no\ need\ to\ check\ error\n\ \ \ \ \}\n\n\ \ \ \ Jim_FreeNewObj(interp,\ holdDict)\;\n\}\n\nset\ savedHoldsLib\ \[\$cc\ compile\]\n\$savedHoldsLib\ init\n\nWhen\ /someone/\ wishes\ to\ deserialize\ namespace\ hold\ with\ directory\ /directory/\ \{\n\ \ \ \ set\ holdFiles\ \[glob\ -nocomplain\ \$directory/*\]\n\n\ \ \ \ foreach\ holdFile\ \$holdFiles\ \{\n\ \ \ \ \ \ \ \ set\ fd\ \[open\ \$holdFile\ r\]\n\ \ \ \ \ \ \ \ set\ holds\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ #\ the\ hold\ file's\ first\ line\ is\ its\ canonical\ name\ (since\n\ \ \ \ \ \ \ \ #\ having\ /\ in\ a\ filename\ would\ mess\ a\ lot\ of\ stuff\ up),\n\ \ \ \ \ \ \ \ #\ while\ the\ rest\ of\ the\ file\ is\ a\ dict\ of\ holds\n\ \ \ \ \ \ \ \ set\ canonicalName\ \[lindex\ \$holds\ 0\]\n\ \ \ \ \ \ \ \ set\ holdDict\ \[lrange\ \$holds\ 1\ end\]\n\n\ \ \ \ \ \ \ \ dict\ for\ \{key\ clause\}\ \$holdDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ \$canonicalName\ -key\ \$key\ --\ \{*\}\$clause\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ loadHolds\ \$canonicalName\ \$holdDict\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ saved\ holds\ are\ loaded\n\}\n\nWhen\ the\ hold\ save\ directory\ is\ /holdDirectory/\ \{\n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk does not ru (
[ m185:0 (s280:0) ]
[ m833:0 (s1285:0 s1286:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/saving/migrate.folk programCode When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /programDirectory/\ &\\\n\ \ \ \ \ saving\ is\ ready\ \{\n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/saving.folk does not run (
[ m187:0 (s283:0) ]
[ m822:0 (s1265:0 s1266:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/saving.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/saving/saving.folk programCode set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\]\}\ \{\n\ \ \ \ file\ mkdir\ \$dataDirectory\n\}\n\n#\ make\ sure\ the\ migration\ happens\ before\ loading\ everything,\n#\ so\ we\ load\ in\ the\ migrated\ data\nWhen\ the\ migration\ is\ complete\ \{\n\ \ \ \ set\ namespaces\ \[glob\ -nocomplain\ \$dataDirectory/*/\]\n\n\ \ \ \ foreach\ namespace\ \$namespaces\ \{\n\ \ \ \ \ \ \ \ set\ namespaceName\ \[file\ tail\ \$namespace\]\n\ \ \ \ \ \ \ \ Wish\ to\ deserialize\ namespace\ \$namespaceName\ with\ directory\ \$namespace\n\ \ \ \ \}\n\}\n\nWhen\ when\ the\ /fileType/\ save\ directory\ is\ /anything/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ set\ serdeDirectory\ \"\$dataDirectory/\$fileType\"\n\n\ \ \ \ #\ make\ sure\ directory\ exists\n\ \ \ \ file\ mkdir\ \$serdeDirectory\n\n\ \ \ \ Claim\ the\ \$fileType\ save\ directory\ is\ \$serdeDirectory\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk does (
[ m188:0 (s284:0) ]
[ m816:0 (s1256:0 s1257:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/saving/save-programs.folk programCode When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk does n (
[ m191:0 (s290:0) ]
[ m810:0 (s1246:0 s1247:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/editor/print-editor.folk programCode fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\}\n\nSubscribe:\ print\ program\ from\ editor\ /editor/\ \{\n\ \ \ \ set\ options\ \[editorToPrintOptions\ \$editor\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\n\n#\ Print\ preview:\nWhen\ the\ codeToPostScript\ is\ /codeToPostScript/\ &\\\n\ \ \ \ \ /someone/\ wishes\ editor\ /editor/\ has\ a\ print\ preview\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/editor.folk does not run (
[ m193:0 (s291:0) ]
[ m804:0 (s1236:0 s1237:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/editor.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/editor/editor.folk programCode #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ later,\ or\ exclude\ keyboards\ that\ opt\ out.\nWhen\ /k/\ is\ a\ keyboard\ with\ /...opts/\ \{\n\ \ \ \ Wish\ tag\ \$k\ is\ stabilized\n\n\ \ \ \ When\ \$k\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ claims\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Create\ a\ synthetic\ editor\ on\ top\ of\ the\ program\ being\ edited,.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editor\ \[list\ \$k\ editor\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ is\ an\ editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ has\ a\ canvas\ with\ layer\ 98\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ has\ resolved\ geometry\ \$geom\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ quad\ /q/\ \{\ Claim\ \$editor\ has\ quad\ \$q\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ has\ created\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$editor\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$program\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ program\ save\ directory\ is\ /programDir/\ &\\\n\ \ \ \ \ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk does n (
[ m195:0 (s295:0) ]
[ m797:0 (s1226:0 s1227:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/editor/editor-utils.folk programCode {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport {originalText x y width height} {
set lines [split $originalText \n]
set lines [lrange $lines $y [expr {($height - 1) + $y}]]
set lines [lmap line $lines {
set line [string range $line $x [expr {($width - 1) + $x}]]
}]
return [join $lines \n]
}
proc cursorToXy {code cursor} {
set codeBeforeCursor [string range $code 0 [- $cursor 1]]
set linesBeforeCursor [split $codeBeforeCursor "\n"]
set lineCountBeforeCursor [llength $linesBeforeCursor]
set cursorX [string length [lindex $linesBeforeCursor end]]
set cursorY [max [- $lineCountBeforeCursor 1] 0]
return [list $cursorX $cursorY]
}
proc xyToCursor {code cursorX cursorY} {
if { $cursorX < 0 } { set cursorX 0 }
if { $cursorY < 0 } { set cursorY 0 }
set lines [split $code "\n"]
set maxCursorY [max 0 [- [llength $lines] 1]]
set cursorY [min $cursorY $maxCursorY]
set relevantLines [lrange $lines 0 [- $cursorY 1]]
set relevantLineLen [string length [lindex $lines $cursorY]]
set joined [join $relevantLines "\n"]
# make sure cursorX < line length
set cursorX [min $cursorX $relevantLineLen]
set cursor [+ [string length $joined] $cursorX]
# don't forget to add the length of \n at the beginning
if {$cursorY > 0} { incr cursor }
return $cursor
}
proc insertText {code cursor newText} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code $cursor end]
set joined [join [list $before $newText $after] ""]
incr cursor
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $joined $cursor $maxCursorX]
}
proc deleteText {code cursor count} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code [+ $cursor $count] end]
set joined [join [list $before $after] ""]
return $joined
}
proc deleteToBeginning {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
set newLine [string range $line $x end]
lset lines $y $newLine
return [join $lines "\n"]
}
proc getLine {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
}
proc getLineLength {code cursor} {
set line [getLine $code $cursor]
set ll [string length $line]
return $ll
}
# returns {newCursor newMaxCursorX}
proc handleNavigation {key code cursor maxCursorX} {
switch $key {
Left {
set cursor [- $cursor 1]
set cursor [max $cursor 0]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Right {
set cursor [+ $cursor 1]
set codeLength [string length $code]
set cursor [min $cursor $codeLength]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Up {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [- $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Down {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [+ $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Control_a {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX 0
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
Control_e {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX [getLineLength $code $cursor]
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
}
return [list $cursor $maxCursorX]
}
# returns {newCode newCursor newMaxCursorX}
proc handleRemovalAndReturn {key code cursor maxCursorX} {
switch $key {
Delete {
if { $cursor != 0 } {
set cursor [- $cursor 1]
set code [deleteText $code $cursor 1]
set maxCursorX [lindex [cursorToXy $code $cursor] 0]
}
}
Remove {
set code [deleteText $code $cursor 1]
}
Control_u {
# delete from cursor back to 0 and move cursor to 0
lassign [cursorToXy $code $cursor] cursorX cursorY
set code [deleteToBeginning $code $cursor]
set newX 0
set cursor [xyToCursor $code $newX $cursorY]
}
Return {
# figure out how many spaces there are before the current line
regexp {^(\s*)} [getLine $code $cursor] -> spacing
set spacingLen [string length $spacing]
lassign [insertText $code $cursor "\n$spacing"] code
set maxCursorX $spacingLen
set cursor [+ $cursor [+ 1 $spacingLen]]
}
}
return [list $code $cursor $maxCursorX]
}
proc getSelectedText {code selAnchor cursor} {
set start [min $selAnchor $cursor]
set end [max $selAnchor $cursor]
return [string range $code $start [- $end 1]]
}
proc replaceRange {code rangeStart rangeEnd newText} {
if {$rangeStart > 0} {
set before [string range $code 0 [- $rangeStart 1]]
} else {
set before ""
}
set after [string range $code $rangeEnd end]
set code "${before}${newText}${after}"
set cursor [+ $rangeStart [string length $newText]]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $code $cursor $maxCursorX]
}
proc lineNumberView {ystart linecount} {
set yend [expr {$ystart + $linecount}]
set numbers [list]
for {set i [expr {$ystart + 1}]} {$i <= $yend} {incr i} {
lappend numbers $i
}
join $numbers "\n"
}
# For rendering:
proc getAdvance {em} {
# From NeomatrixCode.csv
return $(0.5859375 * $em)
}
proc widthAndHeight {resolvedGeom} {
set tagSize [dict get $resolvedGeom tagSize]
set left [dict get $resolvedGeom left]
set right [dict get $resolvedGeom right]
set top [dict get $resolvedGeom top]
set bottom [dict get $resolvedGeom bottom]
set width $($left + $tagSize + $right)
set height $($top + $tagSize + $bottom)
return [list $width $height]
}
# given program and the editor options, figure out how many characters can
# fit in this editor
proc editorSizeInCharacters {margin resolvedGeom options} {
set textScale [dict get $options scale]
set advance [getAdvance $textScale]
lassign [widthAndHeight $resolvedGeom] width height
set width $($width - [lindex $margin 3] - $advance*2.5 - [lindex $margin 1])
set height $($height - [lindex $margin 0] - [lindex $margin 2])
set widthInCharacters $(int($width / $advance))
set heightInCharacters $(int($height / $textScale))
return [list $widthInCharacters $heightInCharacters]
}
}]
}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk does no (
[ m197:0 (s298:0) ]
[ m791:0 (s1217:0 s1218:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/editor/draw-editor.folk programCode When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk does n (
[ m199:0 (s300:0) ]
[ m785:0 (s1208:0 s1209:0) ]
)when the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/decorations/outline.folk programCode When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/decorations/label.folk does not (
[ m200:0 (s302:0) ]
[ m779:0 (s1198:0 s1199:0) ]
)when the collected results for {/any/ wishes program builtin-programs/decorations/label.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/decorations/label.folk programCode {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
}
When /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk does not run} a (
[ m203:0 (s306:0) ]
[ m773:0 (s1189:0 s1190:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/camera/rpi.folk programCode #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ error\ \"Raspberry\ Pi\ camera\ driver\ only\ runs\ on\ Linux.\"\n\}\n\nset\ makeCamera\ \{\n\ \ \ \ set\ cpp\ \[C++\]\n\ \ \ \ \$cpp\ extend\ \$imageLib\n\ \ \ \ \$cpp\ include\ <iostream>\n\ \ \ \ \$cpp\ include\ <iomanip>\n\ \ \ \ \$cpp\ include\ <mutex>\n\ \ \ \ \$cpp\ include\ <condition_variable>\n\ \ \ \ \$cpp\ include\ <queue>\n\ \ \ \ \$cpp\ include\ <sys/mman.h>\n\n\ \ \ \ \$cpp\ include\ <libcamera/libcamera.h>\n\ \ \ \ #\ osnr:\ HACK:\ just\ throwing\ any\ possible\ path\ in.\n\ \ \ \ \$cpp\ cflags\ -I/usr/local/include/libcamera\ -I/usr/include/libcamera\n\ \ \ \ \$cpp\ endcflags\ -lcamera\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ using\ namespace\ libcamera\;\n\n\ \ \ \ \ \ \ \ std::unique_ptr<CameraManager>\ cm\;\n\ \ \ \ \ \ \ \ std::shared_ptr<Camera>\ camera\;\n\tstd::unique_ptr<CameraConfiguration>\ config\;\n\tFrameBufferAllocator\ *allocator\;\n\n\ \ \ \ \ \ \ \ //\ This\ vector\ always\ owns\ all\ the\ request\ objects.\n\tstd::vector<std::unique_ptr<Request>>\ requests\;\n\n\ \ \ \ \ \ \ \ std::mutex\ completedRequestsMutex\;\n\ \ \ \ \ \ \ \ std::queue<Request\ *>\ completedRequests\;\n\ \ \ \ \ \ \ \ std::condition_variable\ completedRequestsCv\;\n\n\ \ \ \ \ \ \ \ uint32_t\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ frameHeight\;\n\ \ \ \ \ \ \ \ uint32_t\ frameBytesPerRow\;\n\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ cameraOpen\ \{char*\ id\ int\ width\ int\ height\}\ void\ \{\n\ \ \ \ \ \ \ \ cm\ =\ std::make_unique<CameraManager>()\;\n\ \ \ \ \ \ \ \ cm->start()\;\n\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ cameras:\"\ <<\ std::endl\;\n\tfor\ (auto\ const\ &camera\ :\ cm->cameras())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"\ -\ \"\ <<\ camera->id()\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ camera\ =\ cm->get(id)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(camera\ !=\ nullptr)\;\n\ \ \ \ \ \ \ \ camera->acquire()\;\n\n\ \ \ \ \ \ \ \ config\ =\ camera->generateConfiguration(\{\ StreamRole::Viewfinder\ \})\;\n\ \ \ \ \ \ \ \ StreamConfiguration\ &streamConfig\ =\ config->at(0)\;\n\ \ \ \ \ \ \ \ streamConfig.size\ =\ Size(width,\ height)\;\n\ \ \ \ \ \ \ \ streamConfig.pixelFormat\ =\ PixelFormat::fromString(\"YUV420\")\;\n\n\ \ \ \ \ \ \ \ config->validate()\;\n\ \ \ \ \ \ \ \ frameWidth\ =\ streamConfig.size.width\;\n\ \ \ \ \ \ \ \ frameHeight\ =\ streamConfig.size.height\;\n\ \ \ \ \ \ \ \ frameBytesPerRow\ =\ streamConfig.stride\;\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"frameWidth:\ \"\ <<\ frameWidth\ <<\ \"\ frameHeight:\ \"\ <<\ frameHeight\ <<\ std::endl\;\n\n\tcamera->configure(config.get())\;\n\n\ \ \ \ \ \ \ \ allocator\ =\ new\ FrameBufferAllocator(camera)\;\n\tfor\ (StreamConfiguration\ &cfg\ :\ *config)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ allocator->allocate(cfg.stream())\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Can't\ allocate\ buffers\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ allocated\ =\ allocator->buffers(cfg.stream()).size()\;\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ Allocated\ \"\ <<\ allocated\ <<\ \"\ buffers\ for\ stream\"\ <<\ std::endl\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (PixelFormat\ &format\ :\ cfg.formats().pixelformats())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ std::cout\ <<\ \"camera/rpi:\ Stream\ supports\ format\ \"\ <<\ format\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (Size\ &size\ :\ cfg.formats().sizes(format))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ \ \ std::cout\ <<\ \"\ \ ->\ supports\ size\ \"\ <<\ size\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\t\}\n\n\ \ \ \ \ \ \ \ Stream\ *stream\ =\ streamConfig.stream()\;\n\ \ \ \ \ \ \ \ assert(streamConfig.pixelFormat.toString()\ ==\ \"YUV420\")\;\n\n\ \ \ \ \ \ \ \ const\ std::vector<std::unique_ptr<FrameBuffer>>\ &buffers\ =\ allocator->buffers(stream)\;\n\tfor\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ buffers.size()\;\ ++i)\ \{\n\t\tstd::unique_ptr<Request>\ request\ =\ camera->createRequest()\;\n\t\tif\ (!request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ create\ request\")\;\n\t\t\}\n\n\t\tconst\ std::unique_ptr<FrameBuffer>\ &buffer\ =\ buffers\[i\]\;\n\t\tint\ ret\ =\ request->addBuffer(stream,\ buffer.get())\;\n\t\tif\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ set\ buffer\ for\ request\")\;\n\t\t\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ControlList\ &controls\ =\ request->controls()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AeEnable,\ false)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::ExposureTime,\ 35000)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AfMode,\ controls::AfModeManual)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Focus\ 30cm\ away\ (0.3m\ ->\ 1/0.3\ =\ 3.3).\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::LensPosition,\ 1.6)\;\n\n\t\trequests.push_back(std::move(request))\;\n\t\}\n\n\tcamera->requestCompleted.connect(requestComplete)\;\n\n\ \ \ \ \ \ \ \ camera->start()\;\n\tfor\ (std::unique_ptr<Request>\ &request\ :\ requests)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(request.get())\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (request->status()\ ==\ Request::RequestCancelled)\ \{\n\t\treturn\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.lock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.push(request)\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.unlock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsCv.notify_one()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ static\ void\ processRequestAndCopyFrame(Request\ *request,\ Image\ im)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ Request::BufferMap\ &buffers\ =\ request->buffers()\;\n\ \ \ \ \ \ \ \ \ \ \ \ assert(buffers.size()\ ==\ 1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (auto\ bufferPair\ :\ buffers)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ (Unused)\ Stream\ *stream\ =\ bufferPair.first\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FrameBuffer\ *buffer\ =\ bufferPair.second\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ FrameMetadata\ &metadata\ =\ buffer->metadata()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(metadata.planes().size()\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(buffer->planes().size()\ ==\ 3)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto\ &plane\ =\ buffer->planes()\[0\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ fd\ =\ plane.fd.get()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *addr\ =\ mmap64(NULL,\ plane.length,\ PROT_READ,\ MAP_PRIVATE,\ fd,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (addr\ ==\ MAP_FAILED)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ MAP_FAILED\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *planeData\ =\ (uint8_t\ *)addr\ +\ plane.offset\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(im.data,\ planeData,\ frameHeight\ *\ frameBytesPerRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ munmap(addr,\ plane.length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ newImage\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ uint32_t\ width\ =\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ height\ =\ frameHeight\;\n\ \ \ \ \ \ \ \ int\ components\ =\ 1\;\n\ \ \ \ \ \ \ \ uint8_t\ *data\ =\ (uint8_t\ *)\ malloc(width*components*height)\;\n\ \ \ \ \ \ \ \ return\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ components,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ width*components,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ freeImage\ \{Image\ image\}\ void\ \{\n\ \ \ \ \ \ \ \ free(image.data)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ grayFrame\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ Request\ *latestRequest\ =\ nullptr\;\n\n\ \ \ \ \ \ \ \ //\ We\ want\ to\ drain\ the\ queue\ of\ completed\ requests.\n\ \ \ \ \ \ \ \ std::unique_lock\ lk(completedRequestsMutex)\;\n\ \ \ \ \ \ \ \ completedRequestsCv.wait(lk,\ \[\]\{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ !completedRequests.empty()\;\n\ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ while\ (!completedRequests.empty())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (latestRequest\ !=\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ We're\ skipping\ this\ request,\ because\ we\ have\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ newer\ one\ in\ the\ queue.\ Requeue\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ latestRequest\ =\ completedRequests.front()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.pop()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lk.unlock()\;\n\n\ \ \ \ \ \ \ \ if\ (latestRequest\ ==\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"No\ new\ frame\ yet\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ newImage()\;\n\ \ \ \ \ \ \ \ processRequestAndCopyFrame(latestRequest,\ im)\;\n\n\ \ \ \ \ \ \ \ /*\ Re-queue\ the\ Request\ to\ the\ camera.\ */\n\ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ compile\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /cameraPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk does not (
[ m204:0 (s308:0) ]
[ m373:0 (s588:0 s592:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/camera/enumerate.folk programCode {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <unistd.h>
$cc include <sys/ioctl.h>
$cc include <linux/videodev2.h>
$cc proc getInfoForCamera {char* camera} Jim_Obj* {
int fd = open(camera, O_RDWR);
FOLK_ENSURE(fd >= 0);
Jim_Obj *infoObj = Jim_NewDictObj(interp, NULL, 0);
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "card", -1),
Jim_NewStringObj(interp, (const char *)cap.card, -1));
}
Jim_Obj *formatsList = Jim_NewListObj(interp, NULL, 0);
// Enumerate pixel formats
struct v4l2_fmtdesc fmt_desc = {0};
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
char fourcc_str[5];
fourcc_str[0] = fmt_desc.pixelformat & 0xFF;
fourcc_str[1] = (fmt_desc.pixelformat >> 8) & 0xFF;
fourcc_str[2] = (fmt_desc.pixelformat >> 16) & 0xFF;
fourcc_str[3] = (fmt_desc.pixelformat >> 24) & 0xFF;
fourcc_str[4] = '\0';
Jim_Obj *resolutionsList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmsizeenum frm_size = {0};
frm_size.pixel_format = fmt_desc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frm_size) == 0) {
if (frm_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Jim_Obj *frameratesList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmivalenum frm_interval = {0};
frm_interval.pixel_format = fmt_desc.pixelformat;
frm_interval.width = frm_size.discrete.width;
frm_interval.height = frm_size.discrete.height;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval) == 0) {
if (frm_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
double fps = (double)frm_interval.discrete.denominator /
frm_interval.discrete.numerator;
Jim_ListAppendElement(interp, frameratesList, Jim_NewDoubleObj(interp, fps));
} else if (frm_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
double min_fps = (double)frm_interval.stepwise.max.denominator /
frm_interval.stepwise.max.numerator;
double max_fps = (double)frm_interval.stepwise.min.denominator /
frm_interval.stepwise.min.numerator;
Jim_Obj *rangeDict = Jim_ObjPrintf("min %f max %f", min_fps, max_fps);
Jim_ListAppendElement(interp, frameratesList, rangeDict);
}
frm_interval.index++;
}
int frameratesLen;
const char *frameratesStr = Jim_GetString(frameratesList, &frameratesLen);
Jim_Obj *resDict = Jim_ObjPrintf("width %u height %u framerates {%s}",
frm_size.discrete.width,
frm_size.discrete.height,
frameratesStr);
Jim_ListAppendElement(interp, resolutionsList, resDict);
}
frm_size.index++;
}
int resolutionsLen;
const char *resolutionsStr = Jim_GetString(resolutionsList, &resolutionsLen);
Jim_Obj *formatDict = Jim_ObjPrintf("fourcc {%s} description {%s} resolutions {%s}",
fourcc_str,
(char*)fmt_desc.description,
resolutionsStr);
Jim_ListAppendElement(interp, formatsList, formatDict);
fmt_desc.index++;
}
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "formats", -1),
formatsList);
close(fd);
return infoObj;
}
set formatsLib [$cc compile]
set camerasByCanonicalName [dict create]
set cameras [glob -nocomplain "/dev/v4l/by-path/*"]
# sort first so the order (and therefore which dedupe wins) is
# consistent across boots.
set cameras [lsort $cameras]
foreach camera $cameras {
# I would prefer to use by-id, but not all cameras show up in
# by-id (webcam on my Dell laptop does not, for instance).
try {
set canonicalName [file readlink $camera]
} on error e {
set canonicalName $camera
}
if {[dict exists $camerasByCanonicalName $canonicalName]} {
# Skip cameras that we already have by another name, so there
# aren't dupes in the enumeration (in particular, by-path
# often has both -usb- and -usbv2- copies of a camera).
continue
}
dict set camerasByCanonicalName $canonicalName $camera
set info [$formatsLib getInfoForCamera $camera]
Claim $::thisNode has camera $camera with {*}$info
}
}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/slice.folk does not run} (
[ m207:0 (s313:0) ]
[ m324:0 (s508:0 s516:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/slice.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/camera/slice.folk programCode #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{\n#\ \ \ \ \ Wish\ \$this\ displays\ camera\ slice\ \$slice\n#\ \}\n\n#\ Callback:\ extract\ out\ a\ camera\ slice\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ camera\ slice\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ intrinsics\ /cameraIntrinsics/\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ frame\ /frame/\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ /p/\ has\ quad\ /q/\ \{\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n\}\n\n#\ Auto-trigger\ callback\ for\ `when\ has\ camera\ slice`\ statements\nWhen\ when\ /p/\ has\ camera\ slice\ /slice/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ -nonatomically\ \$p\ has\ camera\ slice\n\}\n\n#\ Display\ a\ camera\ slice\ (for\ backward\ compatibility).\nWhen\ /someone/\ wishes\ /p/\ displays\ camera\ slice\ /slice/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$slice\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/usb.folk does not run} a (
[ m208:0 (s314:0) ]
[ m220:0 (s352:0 s367:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/usb.folk does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this builtin-programs/camera/usb.folk programCode #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2).\n\nif\ \{\$::tcl_platform(os)\ ne\ \"linux\"\}\ \{\ return\ \}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n\}\n} {}}
when the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk is repl (
[ m231:0 (s354:0) ]
[ m248:0 (s377:0) ]
)when the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/keyboard-shortcuts.folk programCode {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard-shortcuts.folk, match m10029:6: Failed to restart folk.service: Interactive authentication required.
#
# TODO: Figure out how to do this with less powerful permissions than `sudo`. (@cwervo)
# Keyboard shortcuts
# ---
# Alt + Esc: Restart Folk
# Alt + F1: Stop Folk completely (note: need to ssh to restart Folk)
# Alt-Esc on most keyboards
Subscribe: keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
}
# Console_1 corresponds to Alt-F1 on most keyboards
Subscribe: keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/terminal.folk is replaced with (
[ m233:0 (s356:0) ]
[ m250:0 (s384:0) ]
)when the collected results for {/any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/terminal.folk programCode #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/mask-tags.folk is replaced with (
[ m232:0 (s355:0) ]
[ m254:0 (s387:0) ]
)when the collected results for {/any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/mask-tags.folk programCode When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ width\ /projWidth/\ height\ /projHeight/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ intrinsics\ /projectorIntrinsics/\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/errors.folk is replaced with /. (
[ m234:0 (s358:0) ]
[ m255:0 (s390:0) ]
)when the collected results for {/any/ wishes program builtin-programs/errors.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/errors.folk programCode {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
}
When /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/demos.folk is replaced with /.. (
[ m235:0 (s357:0) ]
[ m252:0 (s383:0) ]
)when the collected results for {/any/ wishes program builtin-programs/demos.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/demos.folk programCode {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
Claim 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
Claim 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
Claim 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
Claim 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
Claim 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
Claim 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
Claim 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
Claim 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/group.folk is replaced with /.. (
[ m237:0 (s362:0) ]
[ m257:0 (s392:0) ]
)when the collected results for {/any/ wishes program builtin-programs/group.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/group.folk programCode return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contains\ /...programs/\ \{\n\ \ \ \ Wish\ tag\ \$group\ is\ stabilized\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ claim\ 'tag'\ specifically\ so\ it\ doesn't\ run\ twice\n\ \ \ \ \ \ \ \ Claim\ tag\ \$program\ has\ a\ program\n\ \ \ \ \}\n\}\n\n#\ figure\ out\ the\ text\ to\ display\ below\nWhen\ group\ /group/\ contains\ /...programs/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ /program/\ is\ titled\ /title/\]\ are\ /results/\ \{\n\ \ \ \ set\ programTitles\ \[dict\ create\]\n\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ programId\ \[dict\ get\ \$result\ program\]\n\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$programs\ \$programId\]\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ programTitles\ \$programId\ \[dict\ get\ \$result\ title\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ programTitleText\ \"\"\n\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ set\ title\ \[dict_getdef\ \$programTitles\ \$program\ \"(no\ title)\"\]\n\ \ \ \ \ \ \ \ append\ programTitleText\ \\n\ \$program\ \":\ \"\ \$title\n\ \ \ \ \}\n\n\ \ \ \ Claim\ group\ \$group\ has\ program\ titles\ \$programTitleText\n\}\n\n#\ display\ said\ text\nWhen\ group\ /group/\ has\ program\ titles\ /programTitles/\ &\\\n\ \ \ \ \ /group/\ has\ region\ /r/\ \{\n\ \ \ \ set\ radians\ \[region\ angle\ \$r\]\n\ \ \ \ set\ pos\ \[region\ topleft\ \[region\ move\ \$r\ down\ 40px\ right\ 15px\]\]\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ text\ \$programTitles\ scale\ 0.7\ radians\ \$radians\ anchor\ topleft\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/laser.folk is replaced with /.. (
[ m242:0 (s372:0) ]
[ m264:0 (s401:0) ]
)when the collected results for {/any/ wishes program builtin-programs/laser.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/laser.folk programCode When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/music.folk is replaced with /.. (
[ m244:0 (s380:0) ]
[ m267:0 (s403:0) ]
)when the collected results for {/any/ wishes program builtin-programs/music.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/music.folk programCode {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set musicDir $::env(HOME)/music
exec mkdir -p $musicDir
# https://raw.githubusercontent.com/tidalcycles/Tidal/main/BootTidal.hs
set bootTidal {
:set -XOverloadedStrings
:set prompt ""
import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)
hSetEncoding stdout utf8
tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})
:{
let only = (hush >>)
p = streamReplace tidal
hush = streamHush tidal
panic = do hush
once $ sound "superpanic"
list = streamList tidal
mute = streamMute tidal
unmute = streamUnmute tidal
unmuteAll = streamUnmuteAll tidal
unsoloAll = streamUnsoloAll tidal
solo = streamSolo tidal
unsolo = streamUnsolo tidal
once = streamOnce tidal
first = streamFirst tidal
asap = once
nudgeAll = streamNudgeAll tidal
all = streamAll tidal
resetCycles = streamResetCycles tidal
setCycle = streamSetCycle tidal
setcps = asap . cps
getcps = streamGetcps tidal
getnow = streamGetnow tidal
xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
jump i = transition tidal True (Sound.Tidal.Transition.jump) i
jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
d13 = p 13
d14 = p 14
d15 = p 15
d16 = p 16
:}
:{
let getState = streamGet tidal
setI = streamSetI tidal
setF = streamSetF tidal
setS = streamSetS tidal
setR = streamSetR tidal
setB = streamSetB tidal
:}
:set prompt "tidal> "
:set prompt-cont ""
default (Pattern String, Integer, Double)
}
set scStartup [open $musicDir/startup.sc w]
# via https://club.tidalcycles.org/t/tidal-synth-doesnt-work/800 -- it
# doesn't work if you just do SuperDirt.start; for some reason
puts $scStartup {(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 2048; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt.stop; // stop any old ones, avoid duplicate dirt (if it is nil, this won't do anything)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
SuperDirt.default = ~dirt; // make this instance available in sclang (optional)
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
// directly below here, in your own copy of this file, you could add further code that you want to call on startup
// this makes sure the server and ~dirt are running
// you can keep this separate and make it easier to switch between setups
// by using "path/to/my/file.scd".load and if necessary commenting out different load statements
// ...
};
s.latency = 0.3; // increase this if you get "late" messages
};
);}
close $scStartup
set uid [exec id -u $::env(USER)]
set ::env(DBUS_SESSION_BUS_ADDRESS) "unix:path=/run/user/$uid/bus"
exec rm -f $musicDir/music.log
fn musicExec {args} {
if {[lindex $args end] eq "&"} {
exec {*}[lreplace $args end end] >>$musicDir/music.log 2>>$musicDir/music.log &
} else {
exec {*}$args >>$musicDir/music.log 2>>$musicDir/music.log
}
}
fn musicFinishSetup {} {
if {$::thisNode eq "folk-hex"} {
exec jackd -d alsa -d hdmi:CARD=NVidia -r 48000 -p 1024 -n 2 &
} elseif {$::thisNode eq "folk-sva"} {
exec jackd -d alsa -d hdmi:CARD=Generic,DEV=1 -r 48000 -p 1024 -n 2 &
}
catch {exec pkill ghci}
catch {exec pkill ghc}
catch {exec pkill sclang}
catch {exec pkill scsynth}
sleep 0.4
set ::env(QT_QPA_PLATFORM) offscreen
musicExec sclang $musicDir/startup.sc &
set fifo $musicDir/tidal-input
exec rm -f $fifo
exec mkfifo $fifo
sleep 0.2
musicExec sh -c "ghci < $fifo" &
set fifoId [open $fifo w]
puts $fifoId $bootTidal; flush $fifoId
# We keep $fifoId open so that ghci doesn't get an EOF.
}
while true {
puts "music: Waiting for D-Bus."
sleep 0.2
if {[file exists /run/user/$uid/bus]} {
puts "music: Found D-Bus."
musicFinishSetup
break
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/usb.folk is replaced wit (
[ m247:0 (s382:0) ]
[ m268:0 (s409:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/camera/usb.folk programCode #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2).\n\nif\ \{\$::tcl_platform(os)\ ne\ \"linux\"\}\ \{\ return\ \}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/programs.folk is replaced with (
[ m245:0 (s389:0) ]
[ m272:0 (s412:0) ]
)when the collected results for {/any/ wishes program builtin-programs/programs.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/programs.folk programCode When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{\$tag\ >=\ 48600\}\ \{\ return\ \}\n\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ has\ a\ program\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ is\ a\ tag\n\}\n\nWhen\ -noncapturing\ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/points-at.folk is replaced with (
[ m246:0 (s386:0) ]
[ m269:0 (s406:0) ]
)when the collected results for {/any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/points-at.folk programCode When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ \$l\n\}\n\nWhen\ when\ /rect/\ points\ /direction/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ 1\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /rect/\ points\ /direction/\ with\ length\ /l/\ \{\n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/intersect.folk is replaced with (
[ m278:0 (s424:0) ]
[ m288:0 (s444:0) ]
)when the collected results for {/any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/intersect.folk programCode \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ /r2/\ \{\n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n\}\n\nWhen\ when\ /p/\ has\ neighbor\ /n/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ Wish\ \$p\ has\ neighbors\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/regions.folk is replaced with / (
[ m296:0 (s458:0) ]
[ m305:0 (s472:0) ]
)when the collected results for {/any/ wishes program builtin-programs/regions.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/regions.folk programCode {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1/ has region /r1/ & /p2/ has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}
When /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk is replaced wi (
[ m301:0 (s466:0) ]
[ m313:0 (s487:0) ]
)when the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/terminal-ui.folk programCode {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/apriltags.folk is replaced with (
[ m304:0 (s473:0) ]
[ m315:0 (s497:0) ]
)when the collected results for {/any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/apriltags.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/sprites.folk is replaced with / (
[ m306:0 (s477:0) ]
[ m319:0 (s494:0) ]
)when the collected results for {/any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/sprites.folk programCode ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumbnail\ grid\ with\ 8\ frames\ and\ 4\ columns\n#\ \ \ When\ \$this\ has\ thumbnail\ grid\ /thumbnails/\ \{\n#\ \ \ \ \ Wish\ \$this\ draws\ \$thumbnails\;\ #\ Would\ need\ to\ query\ \$thumnails\ for\ its\ frameCount\ and\ columns\n#\ \ \ \}\n#######\n\n#\ -\ path\ get\ prepended\ with\ ~/folk-images/\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /anyone/\ wishes\ /p/\ draws\ sprite\ /path/\ with\ /...options/\ \{\n\n\ \ set\ frames\ \[dict\ get\ \$options\ frames\]\n\ \ set\ columns\ \[dict\ get\ \$options\ columns\]\n\ \ set\ fps\ \[dict\ getdef\ \$options\ fps\ 60\]\n\n\ \ fn\ loadImage\n\ \ set\ im\ \[loadImage\ \$path\]\n\n\ \ set\ sheetWidth\ \[\$imageLib\ Image_width\ \$im\]\n\ \ set\ sheetHeight\ \[\$imageLib\ Image_height\ \$im\]\n\ \ set\ spriteWidth\ \[/\ \$sheetWidth\ \$columns\]\n\ \ set\ rows\ \[/\ \$frames\ \$columns\]\n\ \ set\ spriteHeight\ \[/\ \$sheetHeight\ \$rows\]\n\n\ \ When\ -atomicallyWithKey\ \[list\ sprite\ \$p\ \$path\]\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ set\ frameNumber\ \[expr\ \{round\ (\$t\ *\ \$fps)\ %\ \$frames\}\]\n\ \ \ \ \ \ set\ x\ \[expr\ \{(\$frameNumber\ %\ \$columns)\ *\ \$spriteWidth\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{(\$frameNumber\ %\ \$rows)\ *\ \$spriteHeight\}\]\n\n\ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$im\ \$x\ \$y\ \$spriteWidth\ \$spriteHeight\]\n\ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$subimage\ with\ \{*\}\$options\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ Wish\ \$this\ draws\ sprite\ \$path\ with\ 8\ frames\ and\ 4\ columns\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/esc-pos.folk is replaced with / (
[ m309:0 (s480:0) ]
[ m317:0 (s492:0) ]
)when the collected results for {/any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/esc-pos.folk programCode When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\n\ \ \ \ fn\ printProgram\ \{printer\ id\ code\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ writeFolkFile\ \$id\ \$code\n\ \ \ \ \ \ \ \ writeMetaFile\ \$printer\ \$id\n\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ is\ at\ /address/\n\ \ \ \ \ \ \ \ set\ printerSocket\ \[socket\ stream\ \$\{address\}:9100\]\n\n\ \ \ \ \ \ \ \ fconfigure\ \$printerSocket\ -translation\ binary\ -buffering\ none\n\ \ \ \ \ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[init\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[tag\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\])\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 2\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[cut\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$printerSocket\ \[render\ \$template\]\n\ \ \ \ \ \ \ \ close\ \$printerSocket\n\ \ \ \ \}\n\n\ \ \ \ fn\ render\ \{template\}\ \{\n\ \ \ \ \ \ \ \ set\ trimmed\ \[lmap\ line\ \[split\ \$template\ \"\\n\"\]\ \{\ string\ trim\ \$line\ \}\]\n\ \ \ \ \ \ \ \ set\ singleLine\ \[join\ \$trimmed\ \"\"\]\n\ \ \ \ \ \ \ \ return\ \[uplevel\ \[list\ subst\ \$singleLine\]\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeFolkFile\ \{id\ code\}\ \{\n\ \ \ \ \ \ \ \ set\ folkFile\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$folkFile\ \$code\n\ \ \ \ \ \ \ \ close\ \$folkFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeMetaFile\ \{printer\ id\}\ \{\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ has\ tag\ geometry\ /geometry/\n\ \ \ \ \ \ \ \ set\ metaFile\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$metaFile\ \[subst\ \{Claim\ tag\ \\\$this\ has\ geometry\ \{\$geometry\}\}\]\n\ \ \ \ \ \ \ \ close\ \$metaFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ cut\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1dV\\x0\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ feed\ n\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"\\x1b\\x64%c\"\ \$n\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ init\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1b\\x40\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ raw\ number\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"%c\"\ \$number\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ scaledAprilTag\ \{id\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ \ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\ \}\ \{\$i\ <\ \$scale\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \[expr\ \{\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ !=\ 255\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \{*\}\[lrepeat\ \$scale\ \$bit\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$tagBits\n\ \ \ \ \}\n\n\ \ \ \ #\ scale\ must\ be\ divisible\ by\ 4\ so\ width\ will\ be\ divisible\ by\ 8\n\ \ \ \ fn\ tag\ \{id\ \{scale\ 12\}\}\ \{\n\ \ \ \ \ \ \ \ set\ tagBits\ \[scaledAprilTag\ \$id\ \$scale\]\n\n\ \ \ \ \ \ \ \ set\ width\ \[expr\ \{10\ *\ \$scale\}\]\n\ \ \ \ \ \ \ \ set\ xL\ \[expr\ \{\$width\ /\ 8\}\]\ \ \ \;#\ width\ in\ bytes\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yL\ \[expr\ \{\$width\ %\ 256\}\]\ \;#\ height\ in\ lines\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yH\ \[expr\ \{\$width\ /\ 256\}\]\ \;#\ height\ in\ lines\ (high\ byte)\n\n\ \ \ \ \ \ \ \ return\ \"\\x1dv0\\x03\[raw\ \$xL\]\\x00\[raw\ \$yL\]\[raw\ \$yH\]\[binary\ format\ B*\ \[join\ \$tagBits\ \"\"\]\]\"\n\ \ \ \ \}\n\n\ \ \ \ Subscribe:\ print\ program\ /id/\ on\ receipt\ printer\ /printer/\ with\ code\ /code/\ \{\n\ \ \ \ \ \ \ \ printProgram\ \$printer\ \$id\ \$code\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/shapes.folk is replaced with /. (
[ m318:0 (s493:0) ]
[ m329:0 (s518:0) ]
)when the collected results for {/any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/shapes.folk programCode set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octagon\ 8\ nonagon\ 9\]\n\nproc\ process_offset\ \{offset\ region\}\ \{\n\ \ if\ \{!\[info\ exists\ region\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ set\ w\ \[region\ width\ \$region\]\n\ \ set\ h\ \[region\ height\ \$region\]\n\ \ \n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \n\ \ \ \ \ \ !\[string\ match\ *%*\ \$offset\]\ &&\ \n\ \ \ \ \ \ !\[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ simple\ percentage\ string:\ \"50%\"\n\ \ if\ \{\[string\ match\ *%*\ \$offset\]\ &&\ \[llength\ \$offset\]\ ==\ 1\}\ \{\n\ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$offset\]\ /\ 100.0\}\]\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \ #\ Default\ to\ horizontal\ offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ strings:\ \"right\",\ \"left\",\ \"up\",\ \"down\"\n\ \ if\ \{\$offset\ eq\ \"right\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"left\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{-\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"up\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ 0.5\}\]\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"down\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{\$h\ *\ 0.5\}\]\]\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ percentage:\ \"right\ 50%\",\ \"left\ 25%\",\ etc.\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ set\ direction\ \[lindex\ \$offset\ 0\]\n\ \ \ \ set\ amount\ \[lindex\ \$offset\ 1\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$amount\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$amount\]\ /\ 100.0\}\]\n\n\ \ \ \ \ \ switch\ \$direction\ \{\n\ \ \ \ \ \ \ \ \"right\"\ \{\ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"left\"\ \ \{\ return\ \[list\ \[expr\ \{-\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"up\"\ \ \ \ \{\ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ \"down\"\ \ \{\ return\ \[list\ 0\ \[expr\ \{\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ default\ \{\ return\ \[list\ 0\ 0\]\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\ \ \n\ \ #\ Handle\ x\ y\ vector\ where\ one\ or\ both\ components\ have\ percentage\ notation\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\}\ \{\n\ \ \ \ lassign\ \$offset\ ox\ oy\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$ox\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$ox\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ ox\ \[expr\ \{\$w\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$oy\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$oy\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ oy\ \[expr\ \{\$h\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ \[list\ \$ox\ \$oy\]\n\ \ \}\n\ \ \n\ \ #\ Default\ fallback\n\ \ return\ \$offset\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ shape\ with\ /...options/\ \{\n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ color\ white\n\}\n\n#\ Handle\ \"a\"\ vs\ \"an\"\ grammar\ variations\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n\}\ \n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ \{\n\ \ \ \ Wish\ \$p\ draws\ text\ \$text\ with\ color\ white\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\n#\ Pass\ through\ options\ for\ \"an\"\ version\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ with\ /...options/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ \{*\}\$options\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ rect\ with\ width\ /w/\ height\ /h/\ \{\n\ \ Wish\ \$p\ draws\ a\ rect\ with\ width\ \$w\ height\ \$h\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ radius\ /rad/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ radius\ \$rad\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ set\ of\ points\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ polyline\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ Center\ circle\n\ \ Wish\ \$this\ draws\ a\ circle\n\ \ \n\ \ #\ Grid\ of\ shapes\ with\ varying\ thickness\n\ \ set\ baseX\ -850\n\ \ set\ baseY\ -200\n\ \ set\ gridSpacing\ 130\n\n\ \ #\ Row\ 0:\ Title\n\ \ Wish\ \$this\ draws\ text\ \"triangle\"\ with\ color\ skyblue\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"square\"\ with\ color\ green\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"pentagon\"\ with\ color\ gold\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"hexagon\"\ with\ color\ orange\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ \n\ \ #\ Row\ 1:\ Regular\ polygons\ with\ different\ colors\ and\ thickness\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ thickness\ 2\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ thickness\ 4\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ thickness\ 6\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ thickness\ 8\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ \n\ \ #\ Row\ 2:\ Filled\ shapes\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ filled\ true\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\n\ \ #\ Row\ 3:\ Directional\ offset\ examples\ (replacing\ shift)\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ radius\ 40\ offset\ \"right\ 50%\"\ color\ skyblue\n\ \ Wish\ \$this\ draws\ a\ square\ with\ radius\ 40\ offset\ \ \"left\ 50%\"\ color\ green\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ radius\ 40\ offset\ \"up\ 50%\"\ color\ gold\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ radius\ 40\ offset\ \"down\ 50%\"\ color\ orange\n\ \ \n\ \ #\ Row\ 4:\ Rectangles\ with\ different\ properties\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ cyan\ thickness\ 3\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ magenta\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \"right\ 50%\"\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \ \"left\ 50%\"\n\ \ \n#\ Animated\ elements\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ angle\ \$r\]\ angle\n\ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 8\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ offsetVector\ \[list\ \[sin\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\ \[*\ 2\ \[cos\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\]\]\n\ \ \ \ \ \ \ \ \ \ set\ vector\ \[::vec2::scale\ \$offsetVector\ \[+\ \[*\ \$i\ \$i\]\ 15\]\]\n\ \ \ \ \ \ \ \ \ \ Wish\ \$this\ draws\ a\ circle\ with\ radius\ \$i\ color\ palegoldenrod\ offset\ \$vector\n\ \ \ \ \ \ \}\n\ \ \}\n\ \ \n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(sin(\$t)\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[-\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[-\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fillVal\"\ color\ red\n\ \ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(\$t\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[+\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[+\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fill\"\ color\ red\n\ \ \}\n\ \ \n\ \ Wish\ \$this\ is\ outlined\ white\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/keyboard.folk is replaced with (
[ m314:0 (s490:0) ]
[ m328:0 (s509:0) ]
)when the collected results for {/any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/keyboard.folk programCode #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ \ \ set\ properties\ \[exec\ udevadm\ info\ --query=property\ --name=\$device\]\n\ \ \ \ if\ \{\$properties\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ false\n\ \ \ \ \}\n\ \ \ \ set\ isKeyboard\ \[string\ match\ *ID_INPUT_KEYBOARD=1*\ \$properties\]\n\ \ \ \ return\ \$isKeyboard\n\ \ \ \ #\ TODO:\ Excluding\ mice\ would\ nice\ to\ keey\ the\ list\ of\ keyboard\ devices\ short\n\ \ \ \ #\ \ \ \ \ \ \ Alas,\ including\ mice\ is\ necessary\ for\ the\ Logitech\ K400R\ keyboard\n\ \ \ \ #\ set\ isMouse\ \[string\ match\ *ID_INPUT_MOUSE=1*\ \$properties\]\n\ \ \ \ #\ return\ \[expr\ \{\$isKeyboard\ &&\ !\$isMouse\}\]\n\}\n\n####\n#\ /dev/input/event*\ addresses\ are\ the\ ground\ truth\ for\ keyboard\ devices\n#\n#\ This\ function\ goes\ through\ each\ of\ them\ and\ checks\ if\ they\ are\ keyboards\nproc\ walkInputEventPaths\ \{\}\ \{\n\ \ \ \ #\ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/event*\"\]\n\ \ \ \ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/by-path/*\"\]\n\ \ \ \ set\ keyboards\ \[list\]\n\ \ \ \ foreach\ device\ \$allDevices\ \{\n\ \ \ \ \ \ \ \ if\ \{\[isKeyboard\ \$device\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[file\ readable\ \$device\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"keyboard:\ Device\ \$device\ is\ not\ readable.\ Attempting\ to\ change\ permissions.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Attempt\ to\ change\ permissions\ so\ that\ the\ file\ can\ be\ read\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ chmod\ +r\ \$device\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ keyboards\ \$device\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$keyboards\n\}\n\nset\ keyboardDevices\ \[walkInputEventPaths\]\nforeach\ keyboard\ \$keyboardDevices\ \{\n\ \ \ \ Claim\ \$keyboard\ is\ a\ keyboard\ device\n\}\n\n#\ backwards\ compatibility\nWhen\ /page/\ is\ a\ keyboard\ with\ path\ /keyboard/\ \{\n\ \ \ \ Claim\ \$page\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ us\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ device\ \{\n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk is replaced (
[ m327:0 (s504:0) ]
[ m336:0 (s542:0) ]
)when the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/tags-to-quads.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/audio.folk is replaced with /.. (
[ m333:0 (s517:0) ]
[ m345:0 (s540:0) ]
)when the collected results for {/any/ wishes program builtin-programs/audio.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/audio.folk programCode #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n#\ ALSA,\ PulseAudio,\ or\ JACK\ drivers.\n#\n#\ See\ https://miniaud.io/.\ We\ are\ using\ Miniaudio\ v0.11.23.\n#\n#\ Examples:\n#\n#\ Play\ a\ sound\ file\ in\ assets/sounds/\ or\ user-programs/\$hostname/sounds:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ drums.wav\n#\n#\ Play\ a\ sound\ file\ by\ absolute\ path:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ /home/folk/sounds/drums.wav\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/miniaudio\n\nif\ \{!\[catch\ \{exec\ which\ sclang\}\]\}\ \{\n\ \ \ \ #\ HACK:\ We're\ running\ msuic.folk\ and\ therefore\ are\ running\ JACK,\n\ \ \ \ #\ so\ we\ should\ force\ miniaudio\ to\ not\ use\ ALSA\ directly\ (because\n\ \ \ \ #\ that\ won't\ work).\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ MA_NO_ALSA\n\ \ \ \ \ \ \ \ #define\ MA_NO_PULSEAUDIO\n\ \ \ \ \}\n\}\n\$cc\ code\ \{\n\ \ \ #define\ MINIAUDIO_IMPLEMENTATION\n\}\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <stdint.h>\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <miniaudio.h>\n\nif\ \{\$::tcl_platform(os)\ ne\ \"Darwin\"\}\ \{\n\ \ \ \ \$cc\ endcflags\ -lpthread\ -lm\ -ldl\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ ma_context\ \ \ \ \ g_ctx\;\n\ \ \ \ static\ ma_engine\ \ \ \ \ \ g_engine\;\n\ \ \ \ static\ ma_sound_group\ g_group\;\n\n\ \ \ \ static\ bool\ g_ctx_initialized\ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_engine_initialized\ =\ false\;\n\ \ \ \ static\ bool\ g_engine_started\ \ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_group_initialized\ \ =\ false\;\n\n\ \ \ \ static\ pthread_mutex_t\ g_state_mtx\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ typedef\ struct\ SoundNode\ \{\n\ \ \ \ \ \ \ \ ma_sound*\ \ \ \ \ \ \ \ \ snd\;\n\ \ \ \ \ \ \ \ struct\ SoundNode*\ next\;\n\ \ \ \ \}\ SoundNode\;\n\n\ \ \ \ static\ SoundNode*\ \ \ \ \ \ g_head\ \ \ \ \ \ \ \ \ \ \ \ =\ NULL\;\n\ \ \ \ static\ pthread_mutex_t\ g_list_mtx\ \ \ \ \ \ \ \ =\ PTHREAD_MUTEX_INITIALIZER\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ \ =\ false\;\n\ \ \ \ static\ pthread_t\ \ \ \ \ \ \ g_reaper_thr\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ /*\ Maintains\ linked\ list\ of\ active\ sounds\ */\n\ \ \ \ static\ bool\ registry_add(ma_sound*\ snd)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ (SoundNode*)malloc(sizeof\ *node)\;\n\n\ \ \ \ \ \ \ \ if\ (!node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ registry_add:\ alloc\ failed\\n\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ node->snd\ =\ snd\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ node->next\ =\ g_head\;\n\ \ \ \ \ \ \ \ g_head\ =\ node\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Removes\ and\ uninitializes\ all\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void\ registry_clear_locked(void)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ next\ =\ node->next\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (node->snd)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(node)\;\n\ \ \ \ \ \ \ \ \ \ \ \ node\ =\ next\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ g_head\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Background\ thread\ that\ periodically\ removes\ finished\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void*\ reaper_main(void*\ arg)\ \{\n\ \ \ \ \ \ \ \ (void)arg\;\n\n\ \ \ \ \ \ \ \ while\ (!g_shutdown_reaper)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ \ node\ \ =\ g_head\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound*\ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ remove\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (snd\ &&\ !ma_sound_is_playing(snd)\ &&\ !ma_sound_is_looping(snd))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Collect\ finished\ sounds\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remove\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (remove)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(to_free)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ usleep(50\ *\ 1000)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ registry_clear_locked()\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ g_reaper_running\ =\ false\;\n\ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ static\ int\ reaper_start(void)\ \{\n\ \ \ \ \ \ \ \ if\ (g_reaper_running)\ return\ 0\;\n\ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ \ \ \ \ int\ err\ =\ pthread_create(&g_reaper_thr,\ NULL,\ reaper_main,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (err\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ err\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Initializes\ the\ audio\ backend\ and\ sound\ group,\ and\ starts\ the\ reaper\ thread\ */\n\ \ \ \ static\ bool\ audio_init_impl(void)\ \{\n\ \ \ \ \ \ \ \ ma_result\ r\;\n\n\ \ \ \ \ \ \ \ if\ (!g_ctx_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_context_init(NULL,\ 0,\ NULL,\ &g_ctx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ context\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_ctx_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ma_engine_config\ cfg\ =\ ma_engine_config_init()\;\n\ \ \ \ \ \ \ \ \ \ \ \ cfg.pContext\ =\ &g_ctx\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_init(&cfg,\ &g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"miniaudio:\ engine\ initialized\ with\ %s\ backend\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_get_backend_name(g_ctx.backend))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_started)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_start(&g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ start\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_group_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_sound_group_init(&g_engine,\ 0,\ NULL,\ &g_group)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ group\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Unwind\ engine\ on\ group\ failure\;\ context\ remains\ for\ future\ attempts\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_engine_uninit(&g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memset(&g_engine,\ 0,\ sizeof\ g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_group_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ err\ =\ reaper_start()\;\n\n\ \ \ \ \ \ \ \ if\ (err\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"audio:\ reaper\ thread\ create\ failed:\ %d\\n\",\ err)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ audioInit\ \{\}\ bool\ \{\n\ \ \ \ pthread_mutex_lock(&g_state_mtx)\;\n\ \ \ \ bool\ success\ =\ audio_init_impl()\;\n\ \ \ \ pthread_mutex_unlock(&g_state_mtx)\;\n\n\ \ \ \ if\ (success)\ \{\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ERROR(\"miniaudio:\ audio\ init\ failed\\n\")\;\n\ \ \ \ return\ false\;\n\}\n\n\$cc\ proc\ audioStop\ \{ma_sound*\ target\}\ void\ \{\n\ \ \ \ SoundNode*\ to_free\ =\ NULL\;\n\ \ \ \ ma_sound*\ snd\ =\ NULL\;\n\n\ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ /*\ Find\ the\ sound\ to\ stop.\ TODO:\ this\ duplicates\ traversal\ logic\ from\ the\ reaper\ thread\ */\n\ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ if\ (node->snd\ ==\ target)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ node->snd\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ /*\ Sound\ already\ reaped\ or\ never\ registered\ */\n\ \ \ \ if\ (!to_free)\ return\;\n\n\ \ \ \ if\ (snd)\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ snd\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ free(to_free)\;\n\}\n\n\$cc\ proc\ playSound\ \{char*\ path\}\ ma_sound*\ \{\n\ \ \ \ ma_sound*\ snd\ =\ (ma_sound*)malloc(sizeof\ *snd)\;\n\n\ \ \ \ if\ (!snd)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ alloc\ sound\ failed\\n\")\;\n\ \ \ \ \}\n\n\ \ \ \ ma_result\ r\ =\ ma_sound_init_from_file(&g_engine,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MA_SOUND_FLAG_DECODE\ |\ MA_SOUND_FLAG_NO_SPATIALIZATION,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &g_group,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ init\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ r\ =\ ma_sound_start(snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ start\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (!registry_add(snd))\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ registry\ add\ failed\ for\ %s\\n\",\ path)\;\n\ \ \ \ \}\n\n\ \ \ \ fprintf(stderr,\ \"miniaudio:\ playing\ %s\\n\",\ path)\;\n\ \ \ \ return\ snd\;\n\}\n\ntry\ \{\n\ \ \ \ set\ audioLib\ \[\$cc\ compile\]\n\ \ \ \ set\ success\ \[\$audioLib\ audioInit\]\n\n\ \ \ \ if\ \{!\$success\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ init\ failed\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ audio\ library\ is\ \$audioLib\n\}\ on\ error\ e\ \{\n\ \ \ \ puts\ stderr\ \"audio:\ compile\ failed:\ \$e\"\n\}\n\nWhen\ the\ audio\ library\ is\ /audioLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ play\ audio\ /sound/\ \{\n\n\ \ \ \ #\ Check\ if\ the\ sound\ file\ exists\ in\ the\ user-programs/\$hostname/sounds\ directory\n\ \ \ \ #\ or\ in\ the\ working\ directory's\ assets/sounds\ subdirectory.\ Otherwise,\ assume\n\ \ \ \ #\ it's\ an\ absolute\ path.\n\ \ \ \ proc\ resolveSoundPath\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ scriptDir\ \[file\ dirname\ \[info\ script\]\]\n\ \ \ \ \ \ \ \ set\ projectRoot\ \[pwd\]\n\ \ \ \ \ \ \ \ set\ hostname\ \[info\ hostname\]\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/user-programs/\$hostname/audio/\$filename\"\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/audio/\$filename\"\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ #\ treat\ as\ an\ absolute\ path\n\ \ \ \ \ \ \ \ return\ \$filename\n\ \ \ \ \}\n\n\ \ \ \ set\ path\ \[resolveSoundPath\ \$sound\]\n\n\ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ File\ not\ found\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ handle\ \[\$audioLib\ playSound\ \$path\]\n\n\ \ \ \ if\ \{\$handle\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ Failed\ to\ play\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ puts\ \"audio:\ stopping\ audio\ '\$path'\"\n\ \ \ \ \ \ \ \ \$audioLib\ audioStop\ \$handle\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/slice.folk is replaced w (
[ m339:0 (s524:0) ]
[ m349:0 (s546:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/camera/slice.folk programCode #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{\n#\ \ \ \ \ Wish\ \$this\ displays\ camera\ slice\ \$slice\n#\ \}\n\n#\ Callback:\ extract\ out\ a\ camera\ slice\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ camera\ slice\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ intrinsics\ /cameraIntrinsics/\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ frame\ /frame/\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ /p/\ has\ quad\ /q/\ \{\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n\}\n\n#\ Auto-trigger\ callback\ for\ `when\ has\ camera\ slice`\ statements\nWhen\ when\ /p/\ has\ camera\ slice\ /slice/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ -nonatomically\ \$p\ has\ camera\ slice\n\}\n\n#\ Display\ a\ camera\ slice\ (for\ backward\ compatibility).\nWhen\ /someone/\ wishes\ /p/\ displays\ camera\ slice\ /slice/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$slice\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk is replaced (
[ m347:0 (s539:0) ]
[ m359:0 (s561:0) ]
)when the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/tags-geometry.folk programCode When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ scaled\ by\ x\ /xScale/\ y\ /yScale/\ \{\n\ \ \ \ proc\ extractMm\ \{mm\}\ \{\n\ \ \ \ \ \ \ \ regexp\ \{(\[0-9.\]+)mm\}\ \$mm\ ->\ extracted\n\ \ \ \ \ \ \ \ return\ \$extracted\n\ \ \ \ \}\n\n\ \ \ \ set\ tagSize\ \[extractMm\ \[dict\ get\ \$defaultGeom\ tagSize\]\]\n\ \ \ \ set\ left\ \[extractMm\ \[dict\ get\ \$defaultGeom\ left\]\]\n\ \ \ \ set\ right\ \[extractMm\ \[dict\ get\ \$defaultGeom\ right\]\]\n\ \ \ \ set\ top\ \[extractMm\ \[dict\ get\ \$defaultGeom\ top\]\]\n\ \ \ \ set\ bottom\ \[extractMm\ \[dict\ get\ \$defaultGeom\ bottom\]\]\n\n\ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\n\ \ \ \ set\ right\ \$(\$right\ +\ (\$width\ *\ \$xScale\ -\ \$width))mm\n\ \ \ \ set\ bottom\ \$(\$bottom\ +\ (\$height\ *\ \$yScale\ -\ \$height))mm\n\n\ \ \ \ set\ newGeom\ \[list\ tagSize\ \$\{tagSize\}mm\ left\ \$\{left\}mm\ right\ \$\{right\}mm\ top\ \$\{top\}mm\ bottom\ \$\{bottom\}mm\]\n\n\ \ \ \ Claim\ tag\ \$program\ has\ geometry\ \$newGeom\n\}\n\nWhen\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /tag/\ has\ resolved\ geometry\ \{\n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/title.folk is replaced with /.. (
[ m351:0 (s547:0) ]
[ m360:0 (s560:0) ]
)when the collected results for {/any/ wishes program builtin-programs/title.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/title.folk programCode #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ titled\ \"This\ is\ a\ tag\"\n#\ Wish\ \$this\ is\ footnoted\ \"This\ is\ a\ footnote\"\n#\ Wish\ \$this\ is\ right-margined\ \"This\ is\ right-margined\ text\"\n#\ Wish\ \$this\ is\ left-margined\ \"This\ is\ left-margined\ text\"\n\nWhen\ /thing/\ has\ quad\ /quad/\ \{\n\ \ \ \ Claim\ -keep\ 50ms\ \$thing\ has\ a\ quad\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /thing/\ has\ a\ quad\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/connections.folk is replaced wi (
[ m348:0 (s544:0) ]
[ m363:0 (s564:0) ]
)when the collected results for {/any/ wishes program builtin-programs/connections.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/connections.folk programCode #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connected\ to\ \$tag2\"\ or\ \"Wish\ \$tag\ is\ dynamically\ connected\ to\ \$tag2\"\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ dynamically\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ sub\ \$sink\ \$source\]\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ grey\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ set\ c\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 2\ color\ \$color\ layer\ \$layer\n\ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ 30\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\}\n\nset\ speed\ 75\nset\ spacing\ 50\nset\ maxsize\ 25\n\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ normalize\ \[vec2\ sub\ \$sink\ \$source\]\]\n\ \ \ set\ distance\ \[vec2\ distance\ \$sink\ \$source\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\ \n\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ lassign\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\ cx\ cy\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 1\ color\ \$color\ layer\ \$layer\n\ \ \ \n\ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ set\ offset\ \[expr\ \{round(\$t*\$speed)\ %\ \$spacing\}\]\n\ \ \ \ \ set\ count\ \[expr\ \{round(\$distance\ /\ \$spacing)\}\]\n\n\ \ \ \ \ for\ \{set\ p\ \$offset\}\ \{\$p\ <\ \$distance\}\ \{incr\ p\ \$spacing\}\ \{\n\ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$source\ \[vec2\ scale\ \$direction\ \$p\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[expr\ \{min(\$maxsize,\ 0.20*min(\$p,\ \$distance\ -\ \$p))\}\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ \$s\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/unix-commands.folk is replaced (
[ m358:0 (s559:0) ]
[ m367:0 (s575:0) ]
)when the collected results for {/any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/unix-commands.folk programCode #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ Wish\ \$this\ runs\ Unix\ command\ \"journalctl\"\ with\ arguments\ \[list\ \"-f\"\ \"-u\"\ \"folk\"\]\nWhen\ /someone/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ with\ arguments\ /args/\ \{\n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n\}\n\n#\ Convenience\ wrapper\ for\ commands\ without\ arguments\nWhen\ /wisher/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ \{\n\tSay\ \$wisher\ wishes\ \$p\ runs\ Unix\ command\ \$command\ with\ arguments\ \[list\]\n\}\n\n#\ When\ /someone/\ wishes\ /p/\ tests\ Unix\ commands\ \{\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"curl\"\ with\ arguments\ \[list\ \"-fsS\"\ \"http://wttr.in/Baltimore?format='%l:+%C'\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"-sSh\"\ \"/home/folk/folk2\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ping\"\ with\ arguments\ \[list\ \"google.com\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"sh\"\ with\ arguments\ \[list\ \"-c\"\ \"while\ :\;\ do\ date\ +%s.%3N\;\ sleep\ 0.5\;\ done\"\]\n\n#\ \t#\ Test\ error\ handling:\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"/nonexistent/path\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"exec\"\ with\ arguments\ \[list\ \"/dev/null\"\]\n\n#\ \tWhen\ \$p\ has\ Unix\ error\ output\ /errorSummary/\ \{\n#\ \t\tputs\ \"errorSummary:\ \$errorSummary\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$errorSummary\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ red\n#\ \t\}\n\n#\ \tWhen\ \$p\ has\ Unix\ output\ lines\ /outputLines/\ \{\n#\ \t\tputs\ \"outputLines:\ \$outputLines\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$outputLines\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ green\n#\ \t\}\n#\ \}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/fswatch.folk is replaced with / (
[ m370:0 (s578:0) ]
[ m376:0 (s589:0) ]
)when the collected results for {/any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/fswatch.folk programCode #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ --recursive\ --event\ Updated\ --event\ Created\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ builtin-programs\ \$::env(HOME)/folk-data/local-program\ \$::env(PWD)/user-programs\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -buffering\ line\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ if\ \{\[gets\ \$fd\ line\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"fswatch:\ fswatch\ failed.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{builtin-programs\\/.*\$\}\ \$line\ changedPath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ changedPath\ \$line\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ changedFilename\ \[file\ tail\ \$changedPath\]\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$changedFilename\ 0\]\ eq\ \".\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$changedFilename\ 0\]\ eq\ \"#\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[file\ extension\ \$changedFilename\]\ ne\ \".folk\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ \"fswatch:\ \$changedPath\ updated,\ ignoring.\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"fswatch:\ \$changedPath\ updated,\ reloading.\"\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$changedPath\ r\]\;\ set\ programCode\ \[read\ \$fp\]\;\ close\ \$fp\n\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 100ms\ -on\ boot.folk\ -key\ \[list\ \$changedPath\ code\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$changedPath\ has\ program\ code\ \$programCode\n\ \ \ \ \}\n\}\ on\ error\ err\ \{\n\ \ \ \ puts\ stderr\ \"fswatch:\ Warning:\ could\ not\ invoke\ `fswatch`\ (\$err).\"\n\ \ \ \ puts\ stderr\ \"fswatch:\ Will\ not\ watch\ builtin-programs\ for\ changes.\"\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk is replac (
[ m379:0 (s596:0) ]
[ m385:0 (s605:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/camera/enumerate.folk programCode {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <unistd.h>
$cc include <sys/ioctl.h>
$cc include <linux/videodev2.h>
$cc proc getInfoForCamera {char* camera} Jim_Obj* {
int fd = open(camera, O_RDWR);
FOLK_ENSURE(fd >= 0);
Jim_Obj *infoObj = Jim_NewDictObj(interp, NULL, 0);
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "card", -1),
Jim_NewStringObj(interp, (const char *)cap.card, -1));
}
Jim_Obj *formatsList = Jim_NewListObj(interp, NULL, 0);
// Enumerate pixel formats
struct v4l2_fmtdesc fmt_desc = {0};
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
char fourcc_str[5];
fourcc_str[0] = fmt_desc.pixelformat & 0xFF;
fourcc_str[1] = (fmt_desc.pixelformat >> 8) & 0xFF;
fourcc_str[2] = (fmt_desc.pixelformat >> 16) & 0xFF;
fourcc_str[3] = (fmt_desc.pixelformat >> 24) & 0xFF;
fourcc_str[4] = '\0';
Jim_Obj *resolutionsList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmsizeenum frm_size = {0};
frm_size.pixel_format = fmt_desc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frm_size) == 0) {
if (frm_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Jim_Obj *frameratesList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmivalenum frm_interval = {0};
frm_interval.pixel_format = fmt_desc.pixelformat;
frm_interval.width = frm_size.discrete.width;
frm_interval.height = frm_size.discrete.height;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval) == 0) {
if (frm_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
double fps = (double)frm_interval.discrete.denominator /
frm_interval.discrete.numerator;
Jim_ListAppendElement(interp, frameratesList, Jim_NewDoubleObj(interp, fps));
} else if (frm_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
double min_fps = (double)frm_interval.stepwise.max.denominator /
frm_interval.stepwise.max.numerator;
double max_fps = (double)frm_interval.stepwise.min.denominator /
frm_interval.stepwise.min.numerator;
Jim_Obj *rangeDict = Jim_ObjPrintf("min %f max %f", min_fps, max_fps);
Jim_ListAppendElement(interp, frameratesList, rangeDict);
}
frm_interval.index++;
}
int frameratesLen;
const char *frameratesStr = Jim_GetString(frameratesList, &frameratesLen);
Jim_Obj *resDict = Jim_ObjPrintf("width %u height %u framerates {%s}",
frm_size.discrete.width,
frm_size.discrete.height,
frameratesStr);
Jim_ListAppendElement(interp, resolutionsList, resDict);
}
frm_size.index++;
}
int resolutionsLen;
const char *resolutionsStr = Jim_GetString(resolutionsList, &resolutionsLen);
Jim_Obj *formatDict = Jim_ObjPrintf("fourcc {%s} description {%s} resolutions {%s}",
fourcc_str,
(char*)fmt_desc.description,
resolutionsStr);
Jim_ListAppendElement(interp, formatsList, formatDict);
fmt_desc.index++;
}
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "formats", -1),
formatsList);
close(fd);
return infoObj;
}
set formatsLib [$cc compile]
set camerasByCanonicalName [dict create]
set cameras [glob -nocomplain "/dev/v4l/by-path/*"]
# sort first so the order (and therefore which dedupe wins) is
# consistent across boots.
set cameras [lsort $cameras]
foreach camera $cameras {
# I would prefer to use by-id, but not all cameras show up in
# by-id (webcam on my Dell laptop does not, for instance).
try {
set canonicalName [file readlink $camera]
} on error e {
set canonicalName $camera
}
if {[dict exists $camerasByCanonicalName $canonicalName]} {
# Skip cameras that we already have by another name, so there
# aren't dupes in the enumeration (in particular, by-path
# often has both -usb- and -usbv2- copies of a camera).
continue
}
dict set camerasByCanonicalName $canonicalName $camera
set info [$formatsLib getInfoForCamera $camera]
Claim $::thisNode has camera $camera with {*}$info
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/display-saver.folk is replaced (
[ m380:0 (s597:0) ]
[ m387:0 (s606:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/display-saver.folk programCode When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor-control.folk is replaced (
[ m383:0 (s603:0) ]
[ m391:0 (s611:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/editor-control.folk programCode When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \"/editor-control\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ html\ \{\n<!DOCTYPE\ html>\n<html\ lang=\"en\">\n\ \ \ \ <head>\n\ \ \ \ \ \ \ \ <meta\ charset=\"utf-8\"\ />\n\ \ \ \ \ \ \ \ <title>Editor\ copy/paste</title>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ </head>\n\ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ \ \ \ \ Select\ a\ keyboard:\ <select\ id=\"keyboard-select\"></select>\n\ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"120\"\ rows=\"40\"></textarea>\n\ \ \ \ \ \ \ \ <script>\nconst\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\nconst\ keyboardSelect\ =\ document.querySelector(\"#keyboard-select\")\;\nconst\ textarea\ =\ document.querySelector(\"#code\")\;\n\nvar\ currentKeyboard\ =\ null\;\nvar\ programCode\ =\ \"\"\;\ //\ not\ the\ same\ as\ editor\ code\nvar\ cursorPosition\ =\ \[0,\ 0\]\;\n\n//\ temporarily\ disable\ event\ processing\ after\ sending\ new\ code\ to\ prevent\ recursive\ event\ sends\nvar\ allowLocalEventsToProcess\ =\ true\;\nvar\ allowRemoteEventsToProcess\ =\ true\;\nvar\ _remoteTimoutHandle\;\nvar\ _localTimeoutHandle\;\nfunction\ disableRemoteEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_remoteTimoutHandle)\ clearTimeout(_remoteTimoutHandle)\;\n\ \ \ \ allowRemoteEventsToProcess\ =\ false\;\n\n\ \ \ \ _remoteTimoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowRemoteEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ disableLocalEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_localTimeoutHandle)\ clearTimeout(_localTimeoutHandle)\;\n\ \ \ \ allowLocalEventsToProcess\ =\ false\;\n\n\ \ \ \ _localTimeoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowLocalEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ updateProgramCode()\ \{\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ currentCode\ =\ textarea.value\;\n\ \ \ \ programCode\ =\ currentCode\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{cursorPosition\[0\]\}\ \$\{cursorPosition\[1\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\nfunction\ updateCursorAndCode(ev)\ \{\n\ \ \ \ if\ (!allowLocalEventsToProcess)\ return\;\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ newCode\ =\ ev.target.value\;\n\n\ \ \ \ //\ figure\ out\ cursor\ position\n\ \ \ \ const\ currentPosition\ =\ textarea.selectionStart\;\n\ \ \ \ const\ linesBefore\ =\ newCode.substring(0,\ currentPosition).split(\"\\n\")\;\n\ \ \ \ const\ y\ =\ linesBefore.length\ -\ 1\;\n\ \ \ \ const\ x\ =\ linesBefore\[linesBefore.length\ -\ 1\].length\;\n\n\ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{x\}\ \$\{y\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(programCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(newCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\ntextarea.addEventListener(\"input\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"selectionchange\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"keydown\",\ ev\ =>\ \{\n\ \ \ \ if(ev.keyCode\ ===\ 83\ /*\ s\ */\ &&\ (navigator.platform.match(\"Mac\")\ ?\ ev.metaKey\ :\ ev.ctrlKey))\ \{\n\ \ \ \ \ \ \ \ ev.preventDefault()\;\n\ \ \ \ \ \ \ \ updateProgramCode()\;\n\ \ \ \ \}\n\})\;\n\nvar\ lastKeyboard\;\ //\ to\ clean\ up\ the\ previous\ keyboard\ when\ another\ is\ picked\nasync\ function\ selectKeyboard(\{\ page,\ kbPath\ \})\ \{\n\ \ \ \ if\ (lastKeyboard)\ lastKeyboard.stop()\;\n\n\ \ \ \ currentKeyboard\ =\ \{\ page,\ kbPath\ \}\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ lastKeyboard\ =\ await\ ws.watch(`\$\{id\}\ has\ base64\ editor\ code\ /editorCode/\ program\ code\ /programCode/\ &\ the\ \$\{kbPath\}\ cursor\ is\ /cursor/`,\ \{\n\ \ \ \ \ \ \ \ add:\ (\{\ editorCode,\ programCode:\ _programCode,\ cursor\ \})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (!allowRemoteEventsToProcess)\ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ disableLocalEventProcessing(500)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ programCode\ =\ atob(_programCode)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ editorCode\ =\ atob(editorCode)\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.value\ =\ editorCode\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ figure\ out\ where\ the\ cursor\ is\n\ \ \ \ \ \ \ \ \ \ \ \ let\ \[x,\ y\]\ =\ loadList(cursor)\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ parseInt(x)\;\ y\ =\ parseInt(y)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ const\ lines\ =\ editorCode.split(\"\\n\")\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ let\ pos\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (let\ i\ =\ 0\;\ i\ <\ y\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ lines\[i\].length\ +\ 1\;\ //\ +\ 1\ for\ newline\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ x\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.focus()\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionStart\ =\ pos\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionEnd\ =\ pos\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \})\;\n\}\n\n//\ update\ keyboard\ list\ as\ it\ changes\nws.watchCollected(\"/page/\ is\ an\ editor\ &\ /page/\ is\ a\ keyboard\ with\ path\ /kbPath/\",\ keyboards\ =>\ \{\n\ \ \ \ keyboardSelect.innerHTML\ =\ \"\"\;\n\n\ \ \ \ for\ (let\ keyboard\ of\ keyboards)\ \{\n\ \ \ \ \ \ \ \ let\ \{page,\ kbPath\}\ =\ keyboard\;\n\ \ \ \ \ \ \ \ keyboardSelect.innerHTML\ +=\ `<option\ value=\"\$\{JSON.stringify(keyboard)\}\">\$\{page\}\ (\$\{kbPath\})</option>`\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (keyboards.length\ ===\ 1)\ \{\n\ \ \ \ \ \ \ \ selectKeyboard(keyboards\[0\])\;\n\ \ \ \ \}\n\})\;\n\n//\ fired\ when\ selected\ keyboard\ changes\nkeyboardSelect.addEventListener(\"input\",\ (ev)\ =>\ \{\n\ \ \ \ selectKeyboard(JSON.parse(ev.target.value))\;\n\})\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/image.folk is replaced wit (
[ m393:0 (s615:0) ]
[ m396:0 (s621:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/image.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*jpg\"\ \$im\]\ ||\ \[string\ match\ \"*jpeg\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$jpegLib\ loadJpeg\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ jpegLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ png\ library\ is\ /pngLib/\ \{\n\ \ \ \ fn\ pngLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*png\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$pngLib\ loadPng\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ pngLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ \ \ fn\ gifLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ upvar\ coerceToImage\ coerceToImage\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gif\ \[\$gifLib\ loadGif\ \$im\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$coerceToImage\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \[lindex\ \[dict\ get\ \$gif\ frames\]\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ WARNING:\ This\ is\ not\ an\ Image\ object\ --\ it's\ a\ Gif\n\ \ \ \ \ \ \ \ \ \ \ \ #\ object\ and\ requires\ special\ handling\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$gif\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ gifLoader\]\ is\ an\ image\ loader\n\}\n\n\nWhen\ the\ collected\ results\ for\ \{/loader/\ is\ an\ image\ loader\}\ are\ /loaders/\ \{\n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"image\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.01)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ return\ texColor\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\}\}\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ image\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ displays\ image\ /impath/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n\}\n\nWhen\ /someone/\ wishes\ /p/\ displays\ image\ /im/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ scale\ 1.0\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk is replaced (
[ m399:0 (s624:0) ]
[ m401:0 (s627:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/apriltags.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ vec4\ background\n\ \ \ \ \ uvec4\ tagBitsVec\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\n\ \ \ \ \ \ \ \ int\ x\ =\ int(uv.x\ *\ 10)\;\ int\ y\ =\ int(uv.y\ *\ 10)\;\n\ \ \ \ \ \ \ \ int\ bitIdx\ =\ y\ *\ 10\ +\ x\;\n\ \ \ \ \ \ \ \ uint\ bit\ =\ (tagBitsVec\[bitIdx\ /\ 32\]\ >>\ (bitIdx\ %\ 32))\ &\ 0x1\;\n\ \ \ \ \ \ \ \ return\ bit\ ==\ 1\ ?\ background\ :\ vec4(0,\ 0,\ 0,\ 1)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /writableTexture/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ AprilTag\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {} {__results {}} {}}
when the collected results for {tag /any/ has a program} are /__results/ {if {[llength $__results] == (
[ m404:0 (s637:0) ]
[ m47706:1055 () ]
)when the collected results for {tag /any/ has a program} are /__results/ {if {[llength $__results] == 0} {When /nobody/ has a display saver & display /disp/ has width /displayWidth/ height /displayHeight/ \n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n}} with environment {{this builtin-programs/display-saver.folk} {} {}}
when the collected results for {/loader/ is an image loader} are /loaders/ \n\ \ \ \ #\ Pass\ coerceT (
[ m420:0 (s669:0) ]
[ m429:0 () ]
[ m948:0 () ]
[ m969:0 () ]
[ m1003:0 (s1774:0) ]
)when the collected results for {/loader/ is an image loader} are /loaders/ \n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n with environment {{this builtin-programs/draw/image.folk} {} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/fill.folk is replaced with (
[ m412:0 (s654:0) ]
[ m419:0 (s666:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/fill.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](p0,\ p1,\ p2,\ p0,\ p0,\ p0)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ return\ color\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ \{\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n\nWhen\ /someone/\ wishes\ /page/\ is\ filled\ with\ /...options/\ &\\\n\ \ \ \ \ /page/\ has\ region\ /region/\ \{\n\ \ set\ points\ \[region\ vertices\ \$region\]\n\ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ \{*\}\$options\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk is replac (
[ m415:0 (s661:0) ]
[ m423:0 (s672:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/dashed-line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\n\ \ \ \ \ float\ dashlength\ float\ dashoffset\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\n\ \ \ \ \ \ \ \ //\ How\ far\ are\ we\ along\ the\ line?\ (in\ pixels)\n\ \ \ \ \ \ \ \ float\ t\ =\ dot(surfaceXy.xy\ -\ from,\ to\ -\ from)\ /\ l\ +\ dashoffset\;\n\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0\ &&\ floor(mod(t\ /\ dashlength,\ 2.0))\ ==\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ dashed\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/line.folk is replaced with (
[ m427:0 (s678:0) ]
[ m433:0 (s692:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/gif.folk is replaced with (
[ m430:0 (s683:0) ]
[ m435:0 (s693:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/gif.folk programCode When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/circle.folk is replaced wi (
[ m439:0 (s703:0) ]
[ m445:0 (s714:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/circle.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ center\ float\ radius\ float\ thickness\ vec4\ color\ int\ filled\}\ \{\n\ \ \ \ \ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ center\ +\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r)\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(surfaceXy.xy\ -\ center)\ -\ radius\;\n\ \ \ \ \ \ \ \ if\ (filled\ ==\ 1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ circle\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk is replaced (
[ m444:0 (s713:0) ]
[ m452:0 (s724:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/color-map.folk programCode {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr {($color >> 8) & 0xFF}]
set r [expr {($color >> 16) & 0xFF}]
return [list [/ $r 255.0] [/ $g 255.0] [/ $b 255.0] 1.0]
}
set colors {
aliceblue F0F8FF
antiquewhite FAEBD7
aqua 00FFFF
aquamarine 7FFFD4
azure F0FFFF
beige F5F5DC
bisque FFE4C4
black 000000
blanchedalmond FFEBCD
blue 0000FF
blueviolet 8A2BE2
brown A52A2A
burlywood DEB887
cadetblue 5F9EA0
chartreuse 7FFF00
chocolate D2691E
coral FF7F50
cornflowerblue 6495ED
cornsilk FFF8DC
crimson DC143C
cyan 00FFFF
darkblue 00008B
darkcyan 008B8B
darkgoldenrod B8860B
darkgray A9A9A9
darkgreen 006400
darkgrey A9A9A9
darkkhaki BDB76B
darkmagenta 8B008B
darkolivegreen 556B2F
darkorange FF8C00
darkorchid 9932CC
darkred 8B0000
darksalmon E9967A
darkseagreen 8FBC8F
darkslateblue 483D8B
darkslategray 2F4F4F
darkslategrey 2F4F4F
darkturquoise 00CED1
darkviolet 9400D3
deeppink FF1493
deepskyblue 00BFFF
dimgray 696969
dimgrey 696969
dodgerblue 1E90FF
firebrick B22222
floralwhite FFFAF0
forestgreen 228B22
fuchsia FF00FF
gainsboro DCDCDC
ghostwhite F8F8FF
gold FFD700
goldenrod DAA520
gray 808080
green 008000
greenyellow ADFF2F
grey 808080
honeydew F0FFF0
hotpink FF69B4
indianred CD5C5C
indigo 4B0082
ivory FFFFF0
khaki F0E68C
lavender E6E6FA
lavenderblush FFF0F5
lawngreen 7CFC00
lemonchiffon FFFACD
lightblue ADD8E6
lightcoral F08080
lightcyan E0FFFF
lightgoldenrodyellow FAFAD2
lightgray D3D3D3
lightgreen 90EE90
lightgrey D3D3D3
lightpink FFB6C1
lightsalmon FFA07A
lightseagreen 20B2AA
lightskyblue 87CEFA
lightslategray 778899
lightslategrey 778899
lightsteelblue B0C4DE
lightyellow FFFFE0
lime 00FF00
limegreen 32CD32
linen FAF0E6
magenta FF00FF
maroon 800000
mediumaquamarine 66CDAA
mediumblue 0000CD
mediumorchid BA55D3
mediumpurple 9370DB
mediumseagreen 3CB371
mediumslateblue 7B68EE
mediumspringgreen 00FA9A
mediumturquoise 48D1CC
mediumvioletred C71585
midnightblue 191970
mintcream F5FFFA
mistyrose FFE4E1
moccasin FFE4B5
navajowhite FFDEAD
navy 000080
oldlace FDF5E6
olive 808000
olivedrab 6B8E23
orange FFA500
orangered FF4500
orchid DA70D6
palegoldenrod EEE8AA
palegreen 98FB98
paleturquoise AFEEEE
palevioletred DB7093
papayawhip FFEFD5
peachpuff FFDAB9
peru CD853F
pink FFC0CB
plum DDA0DD
powderblue B0E0E6
purple 800080
rebeccapurple 663399
red FF0000
rosybrown BC8F8F
royalblue 4169E1
saddlebrown 8B4513
salmon FA8072
sandybrown F4A460
seagreen 2E8B57
seashell FFF5EE
sienna A0522D
silver C0C0C0
skyblue 87CEEB
slateblue 6A5ACD
slategray 708090
slategrey 708090
snow FFFAFA
springgreen 00FF7F
steelblue 4682B4
tan D2B48C
teal 008080
thistle D8BFD8
tomato FF6347
turquoise 40E0D0
violet EE82EE
wheat F5DEB3
white FFFFFF
whitesmoke F5F5F5
yellow FFFF00
yellowgreen 9ACD32
}
set colorMap [dict create]
foreach {color hex} $colors {
dict set colorMap $color [hexcolor $hex]
}
Claim the color map is $colorMap
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk is replaced (
[ m453:0 (s726:0) ]
[ m461:0 (s739:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/image/gif-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced (
[ m458:0 (s732:0) ]
[ m462:0 (s741:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/image/jpeg-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/draw/text.folk is replaced with (
[ m460:0 (s738:0) ]
[ m468:0 (s747:0) ]
)when the collected results for {/any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/draw/text.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk is replace (
[ m465:0 (s744:0) ]
[ m469:0 (s750:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/image/image-lib.folk programCode {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width;
uint32_t height;
int components;
uint32_t bytesPerRow;
// Weird: this can be mutated if you want the image to be
// reloaded into the GPU.
uint64_t uniq;
uint8_t* data;
}
# Note that this returns an image whose lifetime is tied to the original image.
$cc proc slice {Image im double x double y double subwidth double subheight} Image {
uint8_t *subdata = im.data + (int)y*im.bytesPerRow + (int)x*im.components;
return (Image) {
.width = (uint32_t)subwidth,
.height = (uint32_t)subheight,
.components = im.components,
.bytesPerRow = im.bytesPerRow,
.data = subdata,
.uniq = im.uniq
};
}
$cc proc imageNew {int width int height int components int uniq} Image {
uint8_t* data = malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data,
.uniq = uniq
};
}
$cc proc imageFree {Image image} void {
free(image.data);
}
# Note that this returns a fresh (copied) image. imVertices are
# coordinates in im, clockwise from top-left.
$cc proc warpQuad {Image im double[4][2] imVertices
int outWidth int outHeight} Image {
if (outWidth <= 0 || outHeight <= 0 ||
outWidth > (int)im.width * 4 || outHeight > (int)im.height * 4) {
FOLK_ERROR("warpQuad: bad dimensions %d x %d (source %d x %d)",
outWidth, outHeight, im.width, im.height);
}
Image out = imageNew(outWidth, outHeight, im.components, im.uniq);
// imVertices are clockwise from top-left: [TL, TR, BR, BL]
double tlX = imVertices[0][0], tlY = imVertices[0][1];
double trX = imVertices[1][0], trY = imVertices[1][1];
double brX = imVertices[2][0], brY = imVertices[2][1];
double blX = imVertices[3][0], blY = imVertices[3][1];
// For each output pixel, find corresponding source pixel using bilinear mapping
double invW = (outWidth > 1) ? 1.0 / (outWidth - 1) : 0.0;
double invH = (outHeight > 1) ? 1.0 / (outHeight - 1) : 0.0;
for (int y = 0; y < outHeight; y++) {
// Hoist v and y-dependent edge coords outside x-loop
double v = y * invH;
double leftX = tlX + v * (blX - tlX);
double leftY = tlY + v * (blY - tlY);
double rightX = trX + v * (brX - trX);
double rightY = trY + v * (brY - trY);
double stepX = (rightX - leftX) * invW;
double stepY = (rightY - leftY) * invW;
uint8_t *dstRow = out.data + y * out.bytesPerRow;
double srcX = leftX, srcY = leftY;
for (int x = 0; x < outWidth; x++, srcX += stepX, srcY += stepY) {
uint8_t *dstPixel = dstRow + x * out.components;
int ix = (int)srcX;
int iy = (int)srcY;
// Fixed-point fractions (0..255)
int fx = (int)((srcX - ix) * 256);
int fy = (int)((srcY - iy) * 256);
if (ix >= 0 && ix < (int)im.width - 1 && iy >= 0 && iy < (int)im.height - 1) {
uint8_t *p00 = im.data + iy * im.bytesPerRow + ix * im.components;
uint8_t *p10 = p00 + im.components;
uint8_t *p01 = p00 + im.bytesPerRow;
uint8_t *p11 = p01 + im.components;
for (int c = 0; c < im.components; c++) {
int top = p00[c] + ((fx * (p10[c] - p00[c])) >> 8);
int bot = p01[c] + ((fx * (p11[c] - p01[c])) >> 8);
dstPixel[c] = (uint8_t)(top + ((fy * (bot - top)) >> 8));
}
} else if (ix >= 0 && ix < (int)im.width && iy >= 0 && iy < (int)im.height) {
uint8_t *srcPixel = im.data + iy * im.bytesPerRow + ix * im.components;
for (int c = 0; c < im.components; c++) {
dstPixel[c] = srcPixel[c];
}
} else {
for (int c = 0; c < im.components; c++) {
dstPixel[c] = 0;
}
}
}
}
return out;
}
set imageLib [$cc compile]
Claim the image library is $imageLib
fn defineImageArgtype {uvx} {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
}
Claim the image uvx argtype definer is [fn defineImageArgtype]
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk is replaced (
[ m478:0 (s763:0) ]
[ m485:0 (s775:0) ]
)when the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/image/png-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk is replaced (
[ m479:0 (s765:0) ]
[ m484:0 (s774:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/dep-graph.folk programCode set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ create\]\n\ \ \ \ foreach\ stmt\ \[Query!\ /...anything/\]\ \{\n\ \ \ \ \ \ \ \ set\ stmtRef\ \[dict\ get\ \$stmt\ __ref\]\n\ \ \ \ \ \ \ \ set\ label\ \[\$dbLib\ clause\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ label\ \[join\ \[lmap\ line\ \[split\ \$label\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ set\ label\ \[string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$label\]\]\n\ \ \ \ \ \ \ \ set\ stmtParentCount\ \[\$dbLib\ statementParentCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ stmtPtrCount\ \[\$dbLib\ statementPtrCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ \\\[label=\\\"\$stmtRef\ (\$stmtParentCount\ parents)\ (\$stmtPtrCount\ ptrs):\ \$label\\\"\\\]\;\"\n\n\ \ \ \ \ \ \ \ foreach\ childMatchRef\ \[\$dbLib\ childMatches\ \$db\ \$stmtRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ ->\ <\$childMatchRef>\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ matchRefs\ \$childMatchRef\ true\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ foreach\ \{matchRef\ _\}\ \$matchRefs\ \{\n\ \ \ \ \ \ \ \ set\ match\ \[\$dbLib\ matchAcq\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ if\ \{\$match\ eq\ \"(Match*)\ 0x0\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ set\ matchPtrCount\ \[\$dbLib\ matchPtrCount\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ set\ matchIsAlive\ \[\$dbLib\ matchIsAlive\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ \\\[label=\\\"\$matchRef\ (alive?\ \$matchIsAlive)\ (\$matchPtrCount)\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ childStatementRef\ \[\$dbLib\ childStatements\ \$db\ \$matchRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ ->\ <\$childStatementRef>\;\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$dbLib\ matchRel\ \$db\ \$match\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[join\ \$dot\ \"\\n\"\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWhen\ the\ db\ library\ is\ /dbLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/print/print.folk is replaced wi (
[ m482:0 (s766:0) ]
[ m486:0 (s776:0) ]
)when the collected results for {/any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/print/print.folk programCode #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ from\ the\ Web\ UI,\ or\ declare\ it\ using\ Folk:\n#\n#\ \ \ \ \ Assert\ \$::thisNode\ claims\ printer\ \"printer-name\"\ is\ a\ cups\ printer\ with\ url\ \"http://url/ipp/print\"\ driver\ \"everywhere\"\n#\n#\ Lastly,\ you\ need\ to\ declare\ a\ default\ printer\ and\ default\ paper\ format:\n#\ (make\ sure\ that\ the\ default\ printer\ supports\ the\ default\ paper\ format)\n#\n#\ \ \ \ \ Claim\ printer\ my-printer\ is\ the\ default\ printer\n#\ \ \ \ \ Claim\ paper\ format\ a4\ is\ the\ default\ paper\ format\n\nClaim\ the\ paper\ formats\ are\ \{\n\ \ \ \ letter\ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\ \ \ \ a4\ \ \ \ \ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{595\ 842\}\}\n\ \ \ \ indexcard\ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\}\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n\}\n\nSubscribe:\ print\ pdf\ /pdfPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/nav.folk is replaced with / (
[ m497:0 (s790:0) ]
[ m500:0 (s797:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/nav.folk programCode {When the collected results for [list /someone/ wishes the web server handles route /route/ with /...options/] are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
}
}} {} {__results {}} {}}
when the collected results for {/someone/ wishes the web server handles route /route/ with /...option (
[ m506:0 (s803:0) ]
[ m47702:0 () ]
[ m47708:0 () ]
[ m47714:0 () ]
[ m47722:0 () ]
[ m47727:0 (s60114:0) ]
)when the collected results for {/someone/ wishes the web server handles route /route/ with /...options/} are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
} with environment {{this builtin-programs/web/nav.folk} {} {}}
when the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk is replace (
[ m508:0 (s809:0) ]
[ m513:0 (s817:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/block-stats.folk programCode {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/setup.folk is replaced with (
[ m512:0 (s816:0) ]
[ m519:0 (s828:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/setup.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handler\ \{\n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/textures.folk is replaced w (
[ m511:0 (s815:0) ]
[ m520:0 (s826:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/textures.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ draw\ library\ is\ /drawLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ endcflags\ -lpng\n\ \ \ \ \$cc\ cflags\ -I./vendor\n\ \ \ \ \$cc\ endcflags\ \$vmaDll\n\ \ \ \ \$cc\ include\ <png.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ \ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ \ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ to\ make\ gpuLib\ extend\ properly\n\ \ \ \ \$cc\ typedef\ \{struct\ PushConstantsEncoder\}\ PushConstantsEncoder\n\ \ \ \ \$cc\ typedef\ \{struct\ Pipeline\}\ Pipeline\n\ \ \ \ \$cc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\ \ \ \ \$cc\ argtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ \ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ rtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ char\ buf\[100\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ extend\ \$gpuLib\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ extend\ \$gpuTextureLib\n\ \ \ \ \$cc\ proc\ texturesLibInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ volkInitialize()\;\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyTextureFromGpu\ \{GpuTextureHandle\ han\}\ Image\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ getGpuTexture(han)\;\n\ \ \ \ \ \ \ \ if\ (!block->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (Image)\{0\}\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ block->width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ block->height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\ //\ HACK:\ hard-coded\ for\ now\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ block->width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ malloc(block->width\ *\ block->height\ *\ 4)\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ size_t\ stagingBufferSize\ =\ block->width\ *\ block->height\ *\ 4\;\n\ \ \ \ \ \ \ \ createBuffer(stagingBufferSize,\ VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &stagingBuffer,\ &stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n\ \ \ \ \ \ \ \ \ \ \ \ .oldLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .image\ =\ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseMipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.levelCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ image\ to\ buffer\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferOffset\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferRowLength\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferImageHeight\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.mipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageOffset\ =\ \{0,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ .imageExtent\ =\ \{block->width,\ block->height,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdCopyImageToBuffer(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ ®ion\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ image\ layout\ back\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ VkFence\ fence\ =\ getFence()\;\n\ \ \ \ \ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ staging\ buffer\ back\ to\ CPU\n\ \ \ \ \ \ \ \ void*\ data\;\n\ \ \ \ \ \ \ \ vmaMapMemory(vmaGetAllocator(),\ stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ memcpy(im.data,\ data,\ stagingBufferSize)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ //\ Cleanup\ staging\ buffer\n\ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\ stagingBuffer,\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ struct\ WriteState\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ buffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t*\ size\;\ \n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ void\ pngWriteCallback(png_structp\ png_ptr,\ png_bytep\ data,\ png_size_t\ length)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ WriteState*\ state\ =\ (struct\ WriteState*)png_get_io_ptr(png_ptr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(state->buffer\ +\ *state->size,\ data,\ length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ *state->size\ +=\ length\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ imageToPngBuffer\ \{Image\ im\ size_t*\ outSize\}\ uint8_t*\ \{\n\ \ \ \ \ \ \ \ size_t\ bufferSize\ =\ im.width\ *\ im.height\ *\ im.components\ *\ 2\;\ //\ max\ size\ estimate\n\ \ \ \ \ \ \ \ uint8_t*\ buffer\ =\ malloc(bufferSize)\;\n\ \ \ \ \ \ \ \ *outSize\ =\ 0\;\n\n\ \ \ \ \ \ \ \ png_structp\ png_w\ =\ png_create_write_struct(PNG_LIBPNG_VER_STRING,\ NULL,\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (!png_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_infop\ info_w\ =\ png_create_info_struct(png_w)\;\n\ \ \ \ \ \ \ \ if\ (!info_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ struct\ WriteState\ state\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .buffer\ =\ buffer,\n\ \ \ \ \ \ \ \ \ \ \ \ .size\ =\ outSize\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ png_set_write_fn(png_w,\ &state,\ pngWriteCallback,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGBA,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGB,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_bytep*\ row_pointers\ =\ malloc(sizeof(png_bytep)\ *\ im.height)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ row_pointers\[y\]\ =\ im.data\ +\ y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_set_rows(png_w,\ info_w,\ row_pointers)\;\n\ \ \ \ \ \ \ \ png_write_png(png_w,\ info_w,\ PNG_TRANSFORM_IDENTITY,\ NULL)\;\n\n\ \ \ \ \ \ \ \ free(row_pointers)\;\n\ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\n\ \ \ \ \ \ \ \ *outSize\ =\ bufferSize\;\n\ \ \ \ \ \ \ \ return\ buffer\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyAllTexturesFromGpu\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (getGpuTexture(i)->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Image\ im\ =\ copyTextureFromGpu(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pngSize\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ pngData\ =\ imageToPngBuffer(im,\ &pngSize)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_ObjPrintf(\"Image\ %d\ (%d\ x\ %d)\",\ i,\ im.width,\ im.height))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_NewStringObj(interp,\ (char*)pngData,\ pngSize))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(pngData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(im.data)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ set\ texturesLib\ \[\$cc\ compile\]\n\ \ \ \ \$texturesLib\ texturesLibInit\n\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/textures\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ package\ require\ base64\n\n\ \ \ \ \ \ \ \ set\ images\ \[\$texturesLib\ copyAllTexturesFromGpu\]\n\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>Textures</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ img\ \{\ max-width:\ 100%\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{description\ imageData\}\ \$images\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ b64\ \[binary\ encode\ base64\ \$imageData\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \{<div><p>%s</p><img\ src=\"data:image/png\;base64,%s\"></div>\}\ \$description\ \$b64\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/program.folk is replaced wi (
[ m526:0 (s833:0) ]
[ m532:0 (s841:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/program.folk programCode {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/holds.folk is replaced with (
[ m530:0 (s840:0) ]
[ m539:0 (s850:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/holds.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk is replaced wit (
[ m542:0 (s853:0) ]
[ m545:0 (s863:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/db-lib.folk programCode {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
$cc include "db.h"
$cc include "common.h"
$cc include "vendor/stb_ds.h"
$cc code {
typedef struct ListOfEdgeTo {
size_t capacityEdges;
size_t nEdges; // This is an estimate.
uint64_t edges[];
} ListOfEdgeTo;
typedef struct GenRc {
int16_t rc;
int gen: 15;
bool alive: 1;
} GenRc;
#include <pthread.h>
}
set dbCFd [open "db.c" r]; set dbC [read $dbCFd]; close $dbCFd
$cc code [lindex [regexp -inline {typedef struct Destructor \{.*\} Destructor;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct DestructorSet \{.*\} DestructorSet;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Statement \{.*\} Statement;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Match \{.*\} Match;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Hold \{.*\} Hold;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct StatementRefList \{.*\} StatementRefList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersionList \{.*\} AtomicallyVersionList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersion \{.*\} AtomicallyVersion;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Atomically \{.*\} Atomically;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Db \{.*\} Db;} $dbC] 0]
$cc argtype StatementRef { StatementRef $argname; sscanf(Jim_String($obj), "s%d:%d", &$argname.idx, &$argname.gen); }
$cc argtype MatchRef { MatchRef $argname; sscanf(Jim_String($obj), "m%d:%d", &$argname.idx, &$argname.gen); }
$cc proc clauseToJimObj {Clause* clause} Jim_Obj* {
Jim_Obj* termObjs[clause->nTerms];
for (int i = 0; i < clause->nTerms; i++) {
termObjs[i] = Jim_NewStringObj(interp, termPtr(clause->terms[i]),
termLen(clause->terms[i]));
}
return Jim_NewListObj(interp, termObjs, clause->nTerms);
}
$cc proc statementParentCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
int ret = stmt->parentCount;
statementRelease(db, stmt);
return ret;
}
$cc proc statementPtrCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
GenRc genRc = stmt->genRc;
int ret = genRc.rc - 1;
statementRelease(db, stmt);
return ret;
}
$cc proc clause {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewStringObj(interp, "(null)", -1); }
Jim_Obj* ret = clauseToJimObj(statementClause(stmt));
statementRelease(db, stmt);
return ret;
}
$cc proc childMatches {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewEmptyStringObj(interp); }
pthread_mutex_lock(&stmt->childMatchesMutex);
if (stmt->childMatches == NULL) {
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[stmt->childMatches->nEdges];
for (int i = 0; i < stmt->childMatches->nEdges; i++) {
MatchRef child = { .val = stmt->childMatches->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("m%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc matchAcq {Db* db MatchRef matchRef} Match* {
return matchAcquire(db, matchRef);
}
$cc proc matchRel {Db* db Match* match} void {
matchRelease(db, match);
}
$cc proc matchPtrCount {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int ret = genRc.rc - 1;
matchRelease(db, match);
return ret;
}
$cc proc matchIsAlive {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int alive = genRc.alive;
matchRelease(db, match);
return alive;
}
$cc code {
#define CHILD_STATEMENTS_REMOVING ((ListOfEdgeTo*)1)
}
$cc proc childStatements {Db* db MatchRef matchRef} Jim_Obj* {
Match* match = matchAcquire(db, matchRef);
if (match == NULL) { return Jim_NewStringObj(interp, "", -1); }
pthread_mutex_lock(&match->childStatementsMutex);
if (match->childStatements == NULL ||
match->childStatements == CHILD_STATEMENTS_REMOVING) {
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[match->childStatements->nEdges];
for (int i = 0; i < match->childStatements->nEdges; i++) {
StatementRef child = { .val = match->childStatements->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("s%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc countAliveStatements {Db* db} int {
int count = 0;
for (int i = 1; i < 65536; i++) { // slot 0 is reserved
GenRc genRc = db->statementPool[i].genRc;
if (genRc.alive) {
count++;
}
}
return count;
}
$cc proc holds {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->holdsMutex);
for (int i = 0; i < shlen(db->holds); i++) {
Hold* hold = &db->holds[i];
Statement* stmt = statementAcquire(db, hold->statement);
if (stmt == NULL) {
fprintf(stderr, "db-lib: holds: WARNING: held statement on (%s) is invalid! (s%d:%d)\n",
hold->key, hold->statement.idx, hold->statement.gen);
continue;
}
char* clauseStr = clauseToString(statementClause(stmt));
Jim_Obj* holdObjv[] = {
Jim_NewStringObj(interp, hold->key, -1),
Jim_NewIntObj(interp, hold->version),
Jim_ObjPrintf("s%d:%d", hold->statement.idx, hold->statement.gen),
Jim_NewStringObj(interp, clauseStr, -1)
};
statementRelease(db, stmt);
free(clauseStr);
Jim_Obj* holdObj = Jim_NewListObj(interp, holdObjv,
sizeof(holdObjv)/sizeof(holdObjv[0]));
Jim_ListAppendElement(interp, retObj, holdObj);
}
mutexUnlock(&db->holdsMutex);
return retObj;
}
$cc proc atomicallys {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->atomicallysMutex);
for (int i = 0; i < sizeof(db->atomicallys)/sizeof(db->atomicallys[0]); i++) {
Atomically* atomically = &db->atomicallys[i];
if (atomically->key == NULL) { continue; }
// Count versions in allVersions list
int versionCount = 0;
AtomicallyVersionList* vl = atomically->allVersions;
while (vl != NULL) {
versionCount++;
vl = vl->next;
}
// Get latest converged version info
int latestConvergedNumber = -1;
if (atomically->latestConvergedVersion != NULL) {
latestConvergedNumber = atomically->latestConvergedVersion->number;
}
Jim_Obj* atomicallyObjv[] = {
Jim_NewStringObj(interp, atomically->key, -1),
Jim_NewIntObj(interp, latestConvergedNumber),
Jim_NewIntObj(interp, versionCount)
};
Jim_Obj* atomicallyObj = Jim_NewListObj(interp, atomicallyObjv,
sizeof(atomicallyObjv)/sizeof(atomicallyObjv[0]));
Jim_ListAppendElement(interp, retObj, atomicallyObj);
}
mutexUnlock(&db->atomicallysMutex);
return retObj;
}
return [$cc compile]
}}]
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/threads.folk is replaced wi (
[ m546:0 (s862:0) ]
[ m551:0 (s868:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/threads.folk programCode set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ -I./vendor/tracy/public\n\ \ \ \ \$cc\ include\ \"workqueue.h\"\n\ \ \ \ \$cc\ include\ \"common.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ extern\ ThreadControlBlock\ threads\[\]\;\n\ \ \ \ \ \ \ \ extern\ int\ _Atomic\ threadCount\;\n\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ int\ unsafe_workQueueCopy(WorkQueueItem*\ into,\ int\ maxn,\ WorkQueue*\ q)\;\n\ \ \ \ \ \ \ \ extern\ void\ traceItem(char*\ buf,\ size_t\ bufsz,\ WorkQueueItem\ item)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ itemToStringObj(WorkQueueItem\ item)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ char\ buf\[10000\]\;\ traceItem(buf,\ sizeof(buf),\ item)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerTids\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ //\ Fallback\ on\ macOS,\ where\ we\ don't\ have\ /proc\ to\ query\ all\n\ \ \ \ \ \ \ \ //\ threads\ of\ the\ Folk\ process.\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ threads\[i\].tid))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfo\ \{int\ threadIndex\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ if\ (threadIndex\ >=\ threadCount\ ||\ threads\[threadIndex\].tid\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ThreadControlBlock\ *thread\ =\ &threads\[threadIndex\]\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ thread->currentItem\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\ Jim_NewStringObj(interp,\ \"op\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(item))\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ items\[100\]\;\n\ \ \ \ \ \ \ \ int\ nitems\ =\ unsafe_workQueueCopy(items,\ 100,\ thread->workQueue)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ workQueueObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nitems\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ workQueueObj,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(items\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"workQueue\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ workQueueObj)\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"isDeactivated\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ thread->isDeactivated))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"currentItemStartTimestamp\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ObjPrintf(\"%\"\ PRId64,\ thread->currentItemStartTimestamp))\;\n\n\ \ \ \ \ \ \ \ int64_t\ now\ =\ timestamp_get(thread->clockid)\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"elapsed\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ (double)(now\ -\ thread->currentItemStartTimestamp)\ /\ 1000.0))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_allocs\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_allocs))\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_frees\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_frees))\;\n\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfoFromTid\ \{int\ tid\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ ==\ tid)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ workerInfo(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #include\ \"vendor/c11-queues/mpmc_queue.h\"\n\ \ \ \ \ \ \ \ extern\ struct\ mpmc_queue\ globalWorkQueue\;\n\ \ \ \ \ \ \ \ extern\ _Atomic\ int\ globalWorkQueueSize\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ globalWorkQueueAvailable\ \{\}\ size_t\ \{\n\ \ \ \ \ \ \ \ return\ mpmc_queue_available(&globalWorkQueue)\;\n\ \ \ \ \}\n\ \ \ \ #\ Unsafely\ peeks\ at\ the\ queue.\n\ \ \ \ \$cc\ proc\ globalWorkQueueItems\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj\ *ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ size_t\ head\ =\ globalWorkQueue.head\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ head\;\ i\ <\ globalWorkQueue.tail\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ mpmc_queue_cell\ *cell\ =\ &globalWorkQueue.buffer\[i\ &\ globalWorkQueue.buffer_mask\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ *ptr\ =\ cell->data\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ *ptr\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ itemToStringObj(item))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nWish\ the\ web\ server\ handles\ route\ \"/threads\"\ with\ handler\ \{\n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/web.folk is replaced with / (
[ m555:0 (s872:0) ]
[ m560:0 (s882:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/web.folk programCode try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ so\ closing\ a\ tab\ doesn't\ crash\ Folk,\ but\n#\ we\ don't\ want\ to\ block/ignore,\ because\ that\ will\ cause\ child\n#\ processes\ to\ also\ block/ignore\ and\ behave\ weirdly.\nsignal\ handle\ SIGPIPE\n\n#\ To\ force\ a\ rebuild:\ rm\ vendor/wslay/Makefile\nif\ \{!\[file\ exists\ vendor/wslay/Makefile\]\}\ \{\n\ \ \ \ puts\ \"web:\ Configuring\ libwslay...\"\n\ \ \ \ exec\ sh\ -c\ \{cd\ vendor/wslay\ &&\ autoreconf\ -i\ &&\ automake\ &&\ autoconf\ &&\ ./configure\}\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"web:\ Building\ libwslay...\"\nexec\ make\ -C\ vendor/wslay\ >@stdout\ 2>@stderr\nputs\ \"web:\ libwslay\ built.\"\n\nsource\ \"lib/ws.tcl\"\n#\ We\ export\ wsLib\ so\ that\ other\ threads\ can\ emit\ messages\ onto\n#\ websockets.\nClaim\ the\ websocket\ library\ is\ \$wsLib\n\nproc\ handleConnect\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ timeout\ 2000\n\ \ \ \ fileevent\ \$chan\ readable\ \[list\ apply\ \{\{chan\ addr\}\ \{\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleRead\ \$chan\ \$addr\n\ \ \ \ \ \ \ \ \}\ on\ signal\ \{sig\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$sig\ on\ \$chan\ \$addr\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$chan\ \$addr\]\n\}\n\nproc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\nproc\ readFile\ \{filename\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\;\ close\ \$fd\;\ return\ \$response\n\}\n\nproc\ headerGet\ \{headers\ name\ args\}\ \{\n\ \ \ \ foreach\ \{k\ v\}\ \$headers\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ -nocase\ \$k\ \$name\]\}\ \{\ return\ \$v\ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[llength\ \$args\]\ >\ 0\}\ \{\ return\ \[lindex\ \$args\ 0\]\ \}\n\ \ \ \ error\ \"missing\ HTTP\ header\ \$name\"\n\}\n\nproc\ handlePage\ \{path\ httpStatusVar\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ switch\ -exact\ --\ \$path\ \{\n\ \ \ \ \ \ \ \ \"/favicon.ico\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"image/x-icon\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/favicon.ico\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/style.css\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/css\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/style.css\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/lib/folk.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"lib/folk.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/vendor/idiomorph.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"vendor/idiomorph.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ \$httpStatusVar\ httpStatus\n\ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 404\ Not\ Found\"\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <b>\$path</b>\ Not\ found.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ parseQueryString\ \{queryString\}\ \{\n\ \ \ \ set\ QUERY\ \[dict\ create\]\n\ \ \ \ if\ \{\$queryString\ eq\ \"\"\}\ \{\ return\ \$QUERY\ \}\n\n\ \ \ \ set\ queryString\ \[string\ range\ \$queryString\ 1\ end\]\n\ \ \ \ foreach\ pair\ \[split\ \$queryString\ &\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^=\]*)=(.*)\$\}\ \$pair\ ->\ key\ value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ URL\ decode\ key\ and\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$key\ \{\ \}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$key\ \{\[format\ %c\ 0x\\1\]\}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[subst\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$value\ \{\ \}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$value\ \{\[format\ %c\ 0x\\1\]\}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[subst\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ QUERY\ \$key\ \$value\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$QUERY\n\}\n\nfn\ HtmlWhen\ args\ \{\n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n\}\n\nproc\ handleRead\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ buffering\ none\n\n\ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ set\ firstline\ \$line\n\n\ \ \ \ #\ puts\ \"Http\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%H:%M:%S\"\]):\ \$chan\ \$addr:\ \$line\"\n\ \ \ \ set\ headers\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ \ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{\ break\ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ Http:\ (\$line)\"\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^\\s:\]+)\\s*:\\s*(.+)\}\ \$line\ ->\ k\ v\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ headers\ \$k\ \$v\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ stderr\ \"Http:\ Weird\ line:\ \$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[regexp\ \{GET\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\ &&\ \$path\ ne\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ set\ response\ \{\}\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ForEach!\ /someone/\ wishes\ the\ web\ server\ handles\ route\ /route/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ handler\ \[dict\ get\ \$options\ handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[regexp\ -inline\ ^\$\{route\}(\\\\?.*)?\$\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$vars\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ queryString\ \[lindex\ \$vars\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ QUERY\ \[parseQueryString\ \$queryString\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^html\ \[proc\ html\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ text/html\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^json\ \[proc\ json\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ application/json\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$handler\ 0\]\ eq\ \"applyBlock\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ create\ QUERY\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$vars\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ \$i\ \[lindex\ \$vars\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ handler\ 2\ \[linsert\ \[lindex\ \$handler\ 2\]\ end\ \$env\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[\{*\}\$handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varNames\ \[lseq\ \[llength\ \$vars\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ varNames\ QUERY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[apply\ \[list\ \$varNames\ \$handler\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$vars\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$response\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[handlePage\ \$path\ httpStatus\ contentType\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"\$httpStatus\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$response\ statusAndHeaders\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Response\ not\ generated\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ \{err\ opts\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errorInfo\ \[dict\ get\ \$opts\ -errorinfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ src\ \[lindex\ \$errorInfo\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Web\ error\ in\ \$src\ (\$path):\ \$err\\n\ \ \[errorInfo\ \$err\ \$errorInfo\]\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text-html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>folk:\ 500\ Internal\ Server\ Error</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \$err\]:\n\[htmlEscape\ \[errorInfo\ \$err\ \$errorInfo\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 500\ Internal\ Server\ Error\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ statusAndHeaders\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$response\ body\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[regexp\ \{POST\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\}\ \{\n\ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ set\ contentType\ \"text/plain\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"\$httpStatus\\r\\nConnection:\ close\\r\\nContent-Type:\ \$contentType\\r\\n\\r\\n\"\n\n\ \ \ \ \ \ \ \ set\ body\ \[\$chan\ read\ \[headerGet\ \$headers\ Content-Length\]\]\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ (\$body)\"\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[eval\ \$body\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[info\ exists\ path\]\ &&\ \$path\ eq\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"web:\ Request\ for\ /ws\ (\$headers)\"\n\ \ \ \ \ \ \ \ set\ clientKey\ \[headerGet\ \$headers\ Sec-WebSocket-Key\ \"\"\]\n\ \ \ \ \ \ \ \ if\ \{\$clientKey\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"HTTP/1.1\ 400\ Bad\ Request\\r\\nConnection:\ close\\r\\nContent-Type:\ text/plain\;\ charset=utf-8\\r\\n\\r\\nMissing\ Sec-WebSocket-Key\\r\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ WsConnection\ upgrade\ \$chan\ \$clientKey\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ Retract!\ websocket\ \$chan\ is\ connected\]\n\ \ \ \ \ \ \ \ Assert!\ websocket\ \$chan\ is\ connected\n\n\ \ \ \ \}\ else\ \{\ puts\ \"Closing:\ \$chan\ \$addr\ \$headers\"\;\ close\ \$chan\ \}\n\}\n\nwhile\ true\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[socket\ stream.server\ 4273\]\n\ \ \ \ \ \ \ \ \$f\ listen\ 128\n\ \ \ \ \ \ \ \ \$f\ readable\ \[lambda\ \{\}\ \{f\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ client\ \[\$f\ accept\ addr\]\n\ \ \ \ \ \ \ \ \ \ \ \ handleConnect\ \$client\ \$addr\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ break\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ #\ Handles\ failure\ to\ bind\ to\ :4273.\ We\ try\ again\ in\ a\ second.\n\ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$e\"\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\nvwait\ forever\n\n\}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ puts\ \$::realStderr\ \"WARNING:\ web.folk\ failed\ to\ initialize\;\nthe\ web\ server\ is\ probably\ down\;\ check\ /var/tmp/folk-\[pid\]/\ for\ log\ files.\n(Make\ sure\ libtool\ and\ autoconf-archive\ are\ installed.)\n------------------------------------------\n\[errorInfo\ \$e\]\"\n\ \ \ \ return\ -options\ \$opts\ \$e\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/quads.folk is replaced with (
[ m557:0 (s876:0) ]
[ m562:0 (s885:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/quads.folk programCode {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/statements.folk is replaced (
[ m564:0 (s886:0) ]
[ m567:0 (s889:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/statements.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk is replaced (
[ m572:0 (s896:0) ]
[ m574:0 (s899:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/keyboards.folk programCode {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk is replaced (
[ m583:0 (s911:0) ]
[ m587:0 (s918:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/trie-graph.folk programCode set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ \ \ \ \$cc\ include\ <stdlib.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\ \ \ \ \$cc\ include\ \"trie.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ Db\ Db\;\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ void\ dbLockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ void\ dbUnlockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ Trie*\ dbGetClauseToStatementRef(Db*\ db)\;\n\n#ifdef\ TRACY_ENABLE\n\n#include\ <string.h>\nvoid\ *tmalloc(size_t\ sz)\ \{\n\ \ \ \ void\ *ptr\ =\ malloc(sz)\;\n\ \ \ \ TracyCAllocS(ptr,\ sz,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nvoid\ *tcalloc(size_t\ s1,\ size_t\ s2)\ \{\n\ \ \ \ void\ *ptr\ =\ calloc(s1,\ s2)\;\n\ \ \ \ TracyCAllocS(ptr,\ s1\ *\ s2,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nchar\ *tstrdup(const\ char\ *s0)\ \{\n\ \ \ \ int\ sz\ =\ strlen(s0)\ +\ 1\;\n\ \ \ \ char\ *s\ =\ tmalloc(sz)\;\n\ \ \ \ memcpy(s,\ s0,\ sz)\;\n\ \ \ \ return\ s\;\n\}\nvoid\ tfree(void\ *ptr)\ \{\n\ \ \ \ TracyCFreeS(ptr,\ 4)\;\n\ \ \ \ free(ptr)\;\n\}\n\n#else\n\n#define\ tmalloc\ malloc\n#define\ tcalloc\ calloc\n#define\ tstrdup\ strdup\n#define\ tfree\ free\n\n#endif\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ tclify\ \{Trie*\ trie\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ objc\ =\ 3\ +\ trie->branchesCount\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ objv\[objc\]\;\n\ \ \ \ \ \ \ \ objv\[0\]\ =\ Jim_ObjPrintf(\"x%\"\ PRIxPTR,\ (uintptr_t)\ trie)\;\n\ \ \ \ \ \ \ \ objv\[1\]\ =\ trie->key\ ?\ Jim_ObjPrintf(\"%s\",\ trie->key)\ :\ Jim_ObjPrintf(\"ROOT\")\;\n\ \ \ \ \ \ \ \ objv\[2\]\ =\ trie->value\ ?\ Jim_ObjPrintf(\"%\"PRIu64,\ trie->value)\ :\ Jim_ObjPrintf(\"NULL\")\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ trie->branchesCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ HACK:\ const\ isn't\ supported\ yet,\ so\ have\ to\ cast.\n\ \ \ \ \ \ \ \ \ \ \ \ objv\[3+i\]\ =\ trie->branches\[i\]\ ?\ tclify((Trie\ *)trie->branches\[i\])\ :\ Jim_NewStringObj(interp,\ \"\",\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ objv,\ objc)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ dbTrieTclify\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ dbLockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Trie*\ trie\ =\ dbGetClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ tclify(trie)\;\n\ \ \ \ \ \ \ \ dbUnlockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ jimObjToClause\ \{Jim_Obj*\ clauseObj\}\ Clause*\ \{\n\ \ \ \ \ \ \ \ int\ nTerms\ =\ Jim_ListLength(interp,\ clauseObj)\;\n\ \ \ \ \ \ \ \ Clause*\ clause\ =\ clauseNew(nTerms)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ termObj\ =\ Jim_ListGetIndex(interp,\ clauseObj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ termLen\;\n\ \ \ \ \ \ \ \ \ \ \ \ const\ char*\ termStr\ =\ Jim_GetString(termObj,\ &termLen)\;\n\ \ \ \ \ \ \ \ \ \ \ \ clause->terms\[i\]\ =\ termNew(termStr,\ termLen)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ clause\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ clauseToJimObj\ \{Clause*\ clause\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ termObjs\[clause->nTerms\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ clause->nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ termObjs\[i\]\ =\ Jim_NewStringObj(interp,\ termPtr(clause->terms\[i\]),\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ termLen(clause->terms\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ termObjs,\ clause->nTerms)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ new\ \{\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieNew()\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ add\ \{Trie*\ trie\ Jim_Obj*\ patternObj\ uint64_t\ value\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieAdd(trie,\ tmalloc,\ tfree,\ pattern,\ value)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ lookup\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\ =\ trieLookup(trie,\ pattern,\ results,\ 50)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultObjs\[resultCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ resultObjs\[i\]\ =\ Jim_NewIntObj(interp,\ results\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ resultObjs,\ resultCount)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ remove_\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\;\n\ \ \ \ \ \ \ \ trie\ =\ (Trie\ *)trieRemove(trie,\ tmalloc,\ tfree,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pattern,\ results,\ 50,\ &resultCount)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\ \ \ \ \ \ \ \ return\ trie\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nset\ trieDotify\ \{\{trieLib\ tclifiedTrie\}\ \{\n\ \ \ \ local\ proc\ idify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ generate\ id-able\ word\ by\ eliminating\ all\ non-alphanumeric\n\ \ \ \ \ \ \ \ regsub\ -all\ \{\\W+\}\ \$word\ \"_\"\n\ \ \ \ \}\n\ \ \ \ local\ proc\ labelify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ shorten\ the\ longest\ lines\n\ \ \ \ \ \ \ \ set\ word\ \[join\ \[lmap\ line\ \[split\ \$word\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$word\]\n\ \ \ \ \}\n\ \ \ \ local\ proc\ subdot\ \{subtrie\}\ \{\n\ \ \ \ \ \ \ \ set\ branches\ \[lassign\ \$subtrie\ ptr\ key\ id\]\n\n\ \ \ \ \ \ \ \ set\ dot\ \[list\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ \\\[label=\\\"\[labelify\ \$key\]\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ branch\ \$branches\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$branch\ eq\ \{\}\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ branchptr\ \[lindex\ \$branch\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ ->\ \$branchptr\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \[subdot\ \$branch\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[join\ \$dot\ \"\\n\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[subdot\ \$tclifiedTrie\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWish\ the\ web\ server\ handles\ route\ \{/trie-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/page.folk is replaced with (
[ m585:0 (s913:0) ]
[ m588:0 (s919:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/page.folk programCode Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk is replace (
[ m595:0 (s927:0) ]
[ m597:0 (s930:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/atomicallys.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/new.folk is replaced with / (
[ m601:0 (s936:0) ]
[ m603:0 (s939:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/new.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ handler\ \{\n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/log.folk is replaced with / (
[ m609:0 (s947:0) ]
[ m611:0 (s950:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/log.folk programCode {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk is replac (
[ m617:0 (s958:0) ]
[ m619:0 (s961:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/camera-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk is repl (
[ m623:0 (s967:0) ]
[ m625:0 (s970:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/apriltag-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/report.folk is replaced wit (
[ m629:0 (s976:0) ]
[ m631:0 (s979:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/report.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk is re (
[ m635:0 (s985:0) ]
[ m637:0 (s988:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/printed-programs.folk programCode {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/index.folk is replaced with (
[ m643:0 (s996:0) ]
[ m645:0 (s999:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/index.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/web/camera.folk is replaced wit (
[ m651:0 (s1007:0) ]
[ m653:0 (s1010:0) ]
)when the collected results for {/any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/web/camera.folk programCode {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.fol (
[ m659:0 (s1018:0) ]
[ m661:0 (s1021:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/calibration-board.folk programCode #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ -\ paper\ edge\ to\ top\ margin\n#\n#\ -\ paper\ edge\ to\ bottom\ margin\n#\n#\ -\ paper\ edge\ to\ left\ margin\n#\n#\ -\ tag\ inner\ width,\ to\ account\ for\ scaling.\ (We\ also\ want\ this\ tag\n#\ \ \ inner\ width\ to\ be\ exactly\ the\ same\ as\ the\ tag\ inner\ width\ that\ we\n#\ \ \ use\ on\ every\ printed\ program,\ so\ that\ if\ the\ user\ measures\ the\ tag\n#\ \ \ wrong,\ it\ still\ looks\ OK\ on\ the\ average\ program.)\n#\n#\ Then\ we\ can\ correct\ for\ these\ factors\ in\ all\ future\ prints,\ so\ we\n#\ can\ print\ mm-accurate.\n\n#\ These\ values\ are\ all\ in\ points\ (1/72\ of\ an\ inch).\nset\ marginTop\ 48\;\ set\ marginLeft\ 48\n\nset\ measureTop\ \[/\ \$marginTop\ 2\]\;\ set\ measureLeft\ \[/\ \$marginLeft\ 2\]\nset\ tagInnerSideLength\ 70\n\nWhen\ the\ calibration\ measurements\ are\ /measurements/\ \{\n\ \ \ \ set\ m_tag\ \[string\ trimright\ \[dict\ get\ \$measurements\ tagSideLength\]\ mm\]\n\ \ \ \ set\ m_left\ \[string\ trimright\ \[dict\ get\ \$measurements\ left\]\ mm\]\n\ \ \ \ set\ m_bottom\ \[string\ trimright\ \[dict\ get\ \$measurements\ bottom\]\ mm\]\n\n\ \ \ \ #\ Derive\ a\ PostScript\ CTM\ that\ maps\ calibrated\ space\ (origin\ at\n\ \ \ \ #\ paper\ bottom-left,\ 1\ unit\ =\ 1\ physical\ point\ =\ 25.4/72\ mm)\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coordinate\ space.\n\ \ \ \ #\n\ \ \ \ #\ The\ calibration\ board\ was\ printed\ unmediated,\ so\ its\ PS\ coords\n\ \ \ \ #\ are\ the\ printer's\ raw\ coords.\ \ The\ measurement\ lines\ were\ drawn\n\ \ \ \ #\ at\ PS\ positions\ measureLeft\ and\ measureTop\;\ the\ tag\ inner\ side\n\ \ \ \ #\ was\ tagInnerSideLength\ PS\ points.\ \ From\ the\ physical\ measurements\n\ \ \ \ #\ (in\ mm)\ we\ can\ recover\ the\ printer's\ scale\ and\ origin\ offset.\n\ \ \ \ set\ scale\ \[expr\ \{25.4\ *\ \$tagInnerSideLength\ /\ (72.0\ *\ \$m_tag)\}\]\n\ \ \ \ set\ tx\ \[expr\ \{\$measureLeft\ -\ \$m_left\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\ \ \ \ set\ ty\ \[expr\ \{\$measureTop\ -\ \$m_bottom\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\n\ \ \ \ Claim\ the\ calibrated\ print\ scale\ is\ \$scale\n\ \ \ \ Claim\ the\ calibrated\ print\ translation\ is\ \[list\ \$tx\ \$ty\]\n\}\n\nWhen\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ \{\n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk (
[ m665:0 (s1028:0) ]
[ m667:0 (s1031:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/load-calibration.folk programCode When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\}\n\nWhen\ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n\}\n\nWhen\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n\}\n\nWhen\ the\ collected\ results\ for\ \{/somebody/\ claims\ the\ default\ program\ geometry\ is\ /geom/\}\ are\ /results/\ \{\n\ \ \ \ set\ defaultGeometry\ \{tagSize\ 30mm\ top\ 28mm\ right\ 28mm\ left\ 157mm\ bottom\ 80mm\}\n\ \ \ \ set\ shouldClaim\ false\n\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\ ||\n\ \ \ \ \ \ \ \ \[llength\ \$results\]\ ==\ 1\ &&\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\ ==\ \$defaultGeometry\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeometry\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ claims a calibration from camera /cam/ to display /disp/ is /an (
[ m679:0 (s1046:0) ]
[ m681:0 () ]
[ m923:0 () ]
)when the collected results for {/any/ claims a calibration from camera /cam/ to display /disp/ is /anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/load-calibration.folk} {} {}}
when the collected results for {/somebody/ claims the default program geometry is /geom/} are /result (
[ m669:0 (s1036:0) ]
[ m671:0 () ]
[ m675:0 () ]
[ m928:0 () ]
[ m955:0 () ]
)when the collected results for {/somebody/ claims the default program geometry is /geom/} are /results/ {
set defaultGeometry {tagSize 30mm top 28mm right 28mm left 157mm bottom 80mm}
set shouldClaim false
if {[llength $results] == 0 ||
[llength $results] == 1 && [dict get [lindex $results 0] geom] == $defaultGeometry} {
Claim the default program geometry is $defaultGeometry
}
} with environment {{this builtin-programs/calibrate/load-calibration.folk} {} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk i (
[ m684:0 (s1056:0) ]
[ m686:0 (s1059:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/calibrate-page.folk programCode When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk is replace (
[ m690:0 (s1065:0) ]
[ m692:0 (s1068:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/model.folk programCode #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\nClaim\ the\ calibration\ model\ library\ is\ \[library\ create\ modelLib\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\n\n\ \ \ \ variable\ ROWS\ 5\n\ \ \ \ variable\ COLS\ 4\n\ \ \ \ proc\ rows\ \{\}\ \{\ variable\ ROWS\;\ return\ \$ROWS\ \}\n\ \ \ \ proc\ cols\ \{\}\ \{\ variable\ COLS\;\ return\ \$COLS\ \}\n\ \ \ \ #\ A\ model\ is\ a\ dictionary\ whose\ keys\ are\ tag\ IDs\ and\ where\ each\n\ \ \ \ #\ value\ is\ a\ dictionary\ with\ keys\ `c`\ and\ `p`\ which\ are\ model\n\ \ \ \ #\ points\ (x,\ y).\n\ \ \ \ proc\ unitModel\ \{\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ set\ UNIT_MODEL\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ \ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ \ \ \ \ set\ pad\ \[expr\ \{\$tagSideLength\ /\ 3\}\]\n\ \ \ \ \ \ \ \ for\ \{set\ row\ 0\}\ \{\$row\ <\ \$ROWS\}\ \{incr\ row\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ col\ 0\}\ \{\$col\ <\ \$COLS\}\ \{incr\ col\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[expr\ \{48600\ +\ \$row*\$COLS\ +\ \$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$row\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ outer\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{\$modelX\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{\$modelY\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ inner\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopLeft\ \[list\ \$modelX\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[list\ \$modelX\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c\ \[scale\ 0.5\ \[add\ \$modelTopLeft\ \$modelBottomRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p\ \[list\ \$modelBottomLeft\ \$modelBottomRight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelTopRight\ \$modelTopLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ UNIT_MODEL\ \$id\ \$modelTag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$UNIT_MODEL\n\ \ \ \ \}\n\ \ \ \ #\ Tags\ with\ isPrintedTag\ will\ get\ projected\ to\ PostScript\ points\n\ \ \ \ #\ and\ printed\;\ tags\ with\ isProjectedTag\ will\ get\ projected\ to\n\ \ \ \ #\ Vulkan\ points\ and\ rendered\ on\ projector.\n\n\ \ \ \ #\ Tag\ operations.\n\ \ \ \ #\ ---------------\n\n\ \ \ \ proc\ isCalibrationTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ return\ \$(\$id\ >=\ 48600\ &&\ \$id\ <\ 48600\ +\ \$ROWS*\$COLS)\n\ \ \ \ \}\n\ \ \ \ proc\ isPrintedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ COLS\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{int(\$idx\ /\ \$COLS)\}\]\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$idx\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$row\ %\ 2\ ==\ 0\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 1)\ :\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 0)\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\ \ \ \ proc\ isProjectedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{!\[isPrintedTag\ \$id\]\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ isVersionTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$idx\ %\ 4\ ==\ 1\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\n\ \ \ \ #\ Model\ operations.\n\ \ \ \ #\ -----------------\n\n\ \ \ \ #\ Takes\ a\ model\ object\ (dictionary\ of\ tag\ ID\ =>\ \{p,\ c\})\ and\n\ \ \ \ #\ rotates\ version\ tags\ according\ to\ version.\n\ \ \ \ proc\ updateModelVersion\ \{model\ version\}\ \{\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ version\ tag.\ Rotate\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$model\ \$id\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rotatedCorners\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 4\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ rotatedCorners\ \[lindex\ \$p\ \[expr\ \{(\$i\ +\ \$version)\ %\ 4\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ model\ \$id\ p\ \$rotatedCorners\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$model\n\ \ \ \ \}\n\ \ \ \ proc\ scaleModel\ \{model\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ c\ \[scale\ \$scale\ \[dict\ get\ \$tag\ c\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ p\ \[scale\ \$scale\ \[dict\ get\ \$tag\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ proc\ countProjectedTags\ \{model\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\}\ \{\ incr\ i\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$i\n\ \ \ \ \}\n\n\ \ \ \ #\ Detected\ tag-list\ operations.\n\ \ \ \ #\ -----------------------------\n\ \ \ \ proc\ filterProjectedTagsInDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ return\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Find\ a\ version\ tag\ that\ the\ camera\ saw\ and\ check\ its\ rotation\ to\n\ \ \ \ #\ figure\ out\ the\ model\ version\ that\ we're\ seeing.\n\ \ \ \ proc\ detectVersionFromDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ local\ proc\ getTagAngle\ \{tag\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{atan2(-1\ *\ (\[lindex\ \$p\ 1\ 1\]\ -\ \[lindex\ \$p\ 0\ 1\]),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$p\ 1\ 0\]\ -\ \[lindex\ \$p\ 0\ 0\])\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Find\ any\ version\ tag.\ If\ none\ were\ detected,\ then\ abort\n\ \ \ \ \ \ \ \ #\ and\ wait\ until\ a\ later\ frame.\n\ \ \ \ \ \ \ \ foreach\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isVersionTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagId\ \$tag(id)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagAngle\ \[getTagAngle\ \$tag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ versionTagId\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ #\ Compare\ angle\ to\ angle\ of\ any\ other\ projected\ tag.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$detectedTags\]\ <\ 2\}\ \{\ return\ \{\}\ \}\n\ \ \ \ \ \ \ \ foreach\ detectedTag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$detectedTag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\ &&\ !\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ otherTagAngle\ \[getTagAngle\ \$detectedTag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ otherTagAngle\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ set\ versionAngle\ \[expr\ \{\$versionTagAngle\ -\ \$otherTagAngle\}\]\n\ \ \ \ \ \ \ \ #\ Rotations\ corresponding\ to\ versions\ 0,\ 1,\ 2,\ 3:\n\ \ \ \ \ \ \ \ set\ possibleVersions\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ 1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ 1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ -1\]\n\ \ \ \ \ \ \ \ #\ Which\ of\ the\ possibleVersions\ is\ versionAngle\ closest\ to?\n\ \ \ \ \ \ \ \ return\ \[lindex\ \[lsort-indices\ \[lmap\ \{x\ y\}\ \$possibleVersions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{sqrt((\$x\ -\ cos(\$versionAngle))**2\ +\ (\$y\ -\ sin(\$versionAngle))**2)\}\n\ \ \ \ \ \ \ \ \}\]\]\ 0\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ meanTagsDifference\ \{tags1\ tags2\}\ \{\n\ \ \ \ \ \ \ \ set\ diffsum\ 0.0\n\ \ \ \ \ \ \ \ set\ ndiffs\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$tags1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ cheat\ and\ only\ count\ printed\ tags\ so\ we\ don't\ have\ to\n\ \ \ \ \ \ \ \ \ \ \ \ #\ deal\ with\ versioning.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$tags2\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x1\ y1\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tags2\ \$id\ c\]\ x2\ y2\n\ \ \ \ \ \ \ \ \ \ \ \ set\ diffsum\ \[expr\ \{\$diffsum\ +\ sqrt((\$x1\ -\ \$x2)*(\$x1\ -\ \$x2)\ +\ (\$y1\ -\ \$y2)*(\$y1\ -\ \$y2))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ ndiffs\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$ndiffs\ ==\ 0\}\ \{\ return\ Inf\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$diffsum\ /\ \$ndiffs\}\]\n\ \ \ \ \}\n\}\]\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk is re (
[ m696:0 (s1074:0) ]
[ m698:0 (s1077:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/draw-model.folk programCode When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ calibration\ model\ /model/\ \\\n\ \ \ \ \ \ \ \ using\ model-to-display\ homography\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ with\ message\ /calibrationMessage/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk is replac (
[ m702:0 (s1083:0) ]
[ m704:0 (s1086:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/refine.folk programCode #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (or\n#\ \ \ \ \ projector\ calibration,\ equivalently)\ (see\ Zhengyou\ Zhang)\ using\n#\ \ \ \ \ cmpfit.\n#\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk is replaced (
[ m708:0 (s1092:0) ]
[ m710:0 (s1095:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/enumerate.folk programCode {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
$cc proc enumerateDisplays {} Jim_Obj* {
FOLK_ENSURE(volkInitialize() == VK_SUCCESS);
// Create a minimal Vulkan instance for display enumeration.
VkInstance instance;
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* enabledExtensions[] = {
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#ifdef __APPLE__
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
createInfo.ppEnabledExtensionNames = enabledExtensions;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
if (res == VK_ERROR_EXTENSION_NOT_PRESENT) {
FOLK_ERROR("Unable to enumerate displays (for example, this doesn't work on macOS)");
}
FOLK_ERROR("Failed to create Vulkan instance: %d", res);
}
}
volkLoadInstance(instance);
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
vkDestroyInstance(instance, NULL);
return Jim_NewListObj(interp, NULL, 0);
}
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
Jim_Obj *allDisplaysList = Jim_NewListObj(interp, NULL, 0);
// Enumerate displays for each physical device
for (uint32_t devIdx = 0; devIdx < physicalDeviceCount; devIdx++) {
VkPhysicalDevice physicalDevice = physicalDevices[devIdx];
uint32_t displayCount;
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, NULL);
VkDisplayPropertiesKHR displayProps[displayCount];
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProps);
for (uint32_t i = 0; i < displayCount; i++) {
uint32_t modeCount;
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, NULL);
VkDisplayModePropertiesKHR modeProps[modeCount];
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, modeProps);
Jim_Obj *modesList = Jim_NewListObj(interp, NULL, 0);
for (uint32_t j = 0; j < modeCount; j++) {
Jim_Obj *modeDict = Jim_ObjPrintf("visibleRegion {%u %u} refreshRate %u",
modeProps[j].parameters.visibleRegion.width,
modeProps[j].parameters.visibleRegion.height,
modeProps[j].parameters.refreshRate);
Jim_ListAppendElement(interp, modesList, modeDict);
}
int modesLen;
const char *modesStr = Jim_GetString(modesList, &modesLen);
Jim_Obj *displayDict = Jim_ObjPrintf("name {%s} physicalDimensions {%u %u} "
"physicalResolution {%u %u} modes {%s}",
displayProps[i].displayName ? displayProps[i].displayName : "",
displayProps[i].physicalDimensions.width,
displayProps[i].physicalDimensions.height,
displayProps[i].physicalResolution.width,
displayProps[i].physicalResolution.height,
modesStr);
Jim_ListAppendElement(interp, allDisplaysList, displayDict);
}
}
vkDestroyInstance(instance, NULL);
return allDisplaysList;
}
set displayLib [$cc compile]
if {![catch {exec pkg-config --exists glfw3}]} {
Claim $::thisNode has display glfw with info {name "GLFW (windowed)"}
}
try {
foreach display [$displayLib enumerateDisplays] {
Claim $::thisNode has display $display(name) with info $display
}
} finally {
Claim $::thisNode has had displays enumerated
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk is replac (
[ m714:0 (s1100:0) ]
[ m716:0 (s1103:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/matlib.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk is rep (
[ m720:0 (s1109:0) ]
[ m722:0 (s1112:0) ]
)when the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/calibrate/calibrate.folk programCode #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ calibration\n#\ \ \ \ \ pattern\ PDF,\ have\ the\ user\ measure\ its\ real-world\ dimension,\ run\n#\ \ \ \ \ iterative\ projector-camera\ process\ to\ get\ various\ poses\ of\ the\n#\ \ \ \ \ printed\ tags\ alongside\ projected\ tags,\ do\ linear\ fit\ and\ then\n#\ \ \ \ \ nonlinear\ refinement\ to\ find\ intrinsic\ and\ extrinsic\ parameters\n#\ \ \ \ \ for\ the\ camera\ and\ projector.\n#\n#\ \ \ \ \ Closely\ based\ on\ the\ technique\ in\ Audet\ (2009):\n#\ \ \ \ \ http://www.ok.sc.e.titech.ac.jp/res/PCS/publications/procams2009.pdf\n#\n\npackage\ require\ linalg\n\nforeach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\}\ \{\n\ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\}\n\nHold!\ -key\ \{calibration\ poses\ max\}\ \\\n\ \ \ \ Claim\ the\ calibration\ poses\ max\ is\ 10\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ AprilTag\ detector\ maker\ is\ /makeAprilTagDetector/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ calibrate\ camera\ /camera/\ to\ display\ /display/\ \\\n\ \ \ \ \ \ \ \ \ using\ measurements\ /measurements/\ \{\n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nfn\ processHomography\ \{H\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n\}\n\n\n#\ Uses\ Zhang's\ calibration\ technique\n#\ (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf)\n#\ to\ calibrate\ a\ projector\ or\ camera\ given\ a\ known\ 2D\ planar\ pattern\n#\ and\ multiple\ observed\ poses.\n#\n#\ Returns\ intrinsic\ matrix\ for\ the\ camera/projector,\ which\ explains\n#\ how\ 3D\ real-world\ coordinates\ get\ projected\ to\ 2D\ coordinates\ by\n#\ that\ device.\ (The\ intrinsic\ matrix\ can\ be\ used\ with\ an\ AprilTag\n#\ detector\ to\ get\ real-world\ coordinates\ for\ each\ AprilTag.)\n#\n#\ Arguments:\n#\ \ \ \ \ \ \ \ \ width\ \ width\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ height\ height\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ Hs\ \ \ \ \ a\ list\ of\ N\ homographies\ from\ camera/projector\ image\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ plane\ ->\ model\ plane\ (for\ N\ different\ poses).\nfn\ zhangUnrefinedCalibrate\ \{name\ width\ height\ Hs\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n\}\n\nfn\ setCameraToProjectorExtrinsics\ \{modelLib\ calibrationVar\ calibrationPoses\}\ \{\n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n\}\n\n#\ End-to-end\ calibrates\ a\ camera-projector\ pair.\ calibrationPoses\ is\n#\ a\ list\ of\ N\ pose\ dictionaries.\ Each\ pose\ dictionary\ includes\ `tags`\n#\ from\ a\ camera\ detection,\ `model`\ with\ coordinates\ in\ meters,\n#\ `H_modelToDisplay`.\nfn\ unrefinedCalibrateCameraAndProjector\ \{modelLib\ matLib\ calibrationPoses\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n\}\n\nWhen\ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ &\\\n\ \ \ \ \ the\ calibration\ refiner\ is\ /refineCalibration/\ \{\n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk is replaced (
[ m727:0 (s1121:0) ]
[ m729:0 (s1124:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/pipelines.folk programCode #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ compilation.\n#\ \ \ \ \ Created\ once\ (not\ per-display).\ Pipelines\ use\ dynamic\ viewport/scissor\n#\ \ \ \ \ so\ they\ work\ across\ displays\ of\ different\ sizes.\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk is replaced with / (
[ m733:0 (s1130:0) ]
[ m735:0 (s1133:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/gpu.folk programCode {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq "darwin"} {
# We hard-code gpu.folk into thread 0, so we should abort if not
# running that way.
return
}
fn defineVulkanHandleType {cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
}
Claim the GPU Vulkan handle type definer is [fn defineVulkanHandleType]
fn gpuInit {useGlfw} {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
}
if {$::tcl_platform(os) eq "darwin"} {
gpuInit true
return
}
When $::thisNode has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk is replaced w (
[ m740:0 (s1141:0) ]
[ m742:0 (s1144:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/textures.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk is replaced with (
[ m747:0 (s1151:0) ]
[ m749:0 (s1154:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/draw.folk programCode #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ and\n#\ \ \ \ \ numerical\ parameters\ (so\ you\ can\ draw\ images,\ shapes,\ etc.)\n#\ \ \ \ \ Single\ render\ thread\ handles\ all\ displays.\n\nif\ \{\[info\ exists\ this\]\ &&\ \$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ #\ We\ hard-code\ draw.folk\ into\ thread\ 0,\ so\ we\ should\ abort\ if\ not\n\ \ \ \ #\ running\ that\ way.\n\ \ \ \ return\n\}\n\nWhen\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ compiler\ library\ is\ /pipelineCompilerLib/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced (
[ m753:0 (s1160:0) ]
[ m755:0 (s1163:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/toy-shader.folk programCode #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <openssl/sha.h>\n\$cc\ proc\ sha1\ \{char*\ d\}\ Jim_Obj*\ \{\n\ \ \ \ unsigned\ char\ md\[20\]\;\n\ \ \ \ SHA1((unsigned\ char\ *)d,\ strlen(d),\ md)\;\n\ \ \ \ return\ Jim_NewStringObj(interp,\ (char\ *)md,\ 20)\;\n\}\n\$cc\ endcflags\ -lssl\ -lcrypto\nset\ sha1Lib\ \[\$cc\ compile\]\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ \{\n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk is replaced w (
[ m761:0 (s1171:0) ]
[ m763:0 (s1174:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/canvases.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk is replaced with / (
[ m767:0 (s1180:0) ]
[ m769:0 (s1183:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/vma.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk is replaced wit (
[ m774:0 (s1191:0) ]
[ m776:0 (s1194:0) ]
)when the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/camera/rpi.folk programCode #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ error\ \"Raspberry\ Pi\ camera\ driver\ only\ runs\ on\ Linux.\"\n\}\n\nset\ makeCamera\ \{\n\ \ \ \ set\ cpp\ \[C++\]\n\ \ \ \ \$cpp\ extend\ \$imageLib\n\ \ \ \ \$cpp\ include\ <iostream>\n\ \ \ \ \$cpp\ include\ <iomanip>\n\ \ \ \ \$cpp\ include\ <mutex>\n\ \ \ \ \$cpp\ include\ <condition_variable>\n\ \ \ \ \$cpp\ include\ <queue>\n\ \ \ \ \$cpp\ include\ <sys/mman.h>\n\n\ \ \ \ \$cpp\ include\ <libcamera/libcamera.h>\n\ \ \ \ #\ osnr:\ HACK:\ just\ throwing\ any\ possible\ path\ in.\n\ \ \ \ \$cpp\ cflags\ -I/usr/local/include/libcamera\ -I/usr/include/libcamera\n\ \ \ \ \$cpp\ endcflags\ -lcamera\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ using\ namespace\ libcamera\;\n\n\ \ \ \ \ \ \ \ std::unique_ptr<CameraManager>\ cm\;\n\ \ \ \ \ \ \ \ std::shared_ptr<Camera>\ camera\;\n\tstd::unique_ptr<CameraConfiguration>\ config\;\n\tFrameBufferAllocator\ *allocator\;\n\n\ \ \ \ \ \ \ \ //\ This\ vector\ always\ owns\ all\ the\ request\ objects.\n\tstd::vector<std::unique_ptr<Request>>\ requests\;\n\n\ \ \ \ \ \ \ \ std::mutex\ completedRequestsMutex\;\n\ \ \ \ \ \ \ \ std::queue<Request\ *>\ completedRequests\;\n\ \ \ \ \ \ \ \ std::condition_variable\ completedRequestsCv\;\n\n\ \ \ \ \ \ \ \ uint32_t\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ frameHeight\;\n\ \ \ \ \ \ \ \ uint32_t\ frameBytesPerRow\;\n\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ cameraOpen\ \{char*\ id\ int\ width\ int\ height\}\ void\ \{\n\ \ \ \ \ \ \ \ cm\ =\ std::make_unique<CameraManager>()\;\n\ \ \ \ \ \ \ \ cm->start()\;\n\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ cameras:\"\ <<\ std::endl\;\n\tfor\ (auto\ const\ &camera\ :\ cm->cameras())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"\ -\ \"\ <<\ camera->id()\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ camera\ =\ cm->get(id)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(camera\ !=\ nullptr)\;\n\ \ \ \ \ \ \ \ camera->acquire()\;\n\n\ \ \ \ \ \ \ \ config\ =\ camera->generateConfiguration(\{\ StreamRole::Viewfinder\ \})\;\n\ \ \ \ \ \ \ \ StreamConfiguration\ &streamConfig\ =\ config->at(0)\;\n\ \ \ \ \ \ \ \ streamConfig.size\ =\ Size(width,\ height)\;\n\ \ \ \ \ \ \ \ streamConfig.pixelFormat\ =\ PixelFormat::fromString(\"YUV420\")\;\n\n\ \ \ \ \ \ \ \ config->validate()\;\n\ \ \ \ \ \ \ \ frameWidth\ =\ streamConfig.size.width\;\n\ \ \ \ \ \ \ \ frameHeight\ =\ streamConfig.size.height\;\n\ \ \ \ \ \ \ \ frameBytesPerRow\ =\ streamConfig.stride\;\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"frameWidth:\ \"\ <<\ frameWidth\ <<\ \"\ frameHeight:\ \"\ <<\ frameHeight\ <<\ std::endl\;\n\n\tcamera->configure(config.get())\;\n\n\ \ \ \ \ \ \ \ allocator\ =\ new\ FrameBufferAllocator(camera)\;\n\tfor\ (StreamConfiguration\ &cfg\ :\ *config)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ allocator->allocate(cfg.stream())\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Can't\ allocate\ buffers\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ allocated\ =\ allocator->buffers(cfg.stream()).size()\;\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ Allocated\ \"\ <<\ allocated\ <<\ \"\ buffers\ for\ stream\"\ <<\ std::endl\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (PixelFormat\ &format\ :\ cfg.formats().pixelformats())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ std::cout\ <<\ \"camera/rpi:\ Stream\ supports\ format\ \"\ <<\ format\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (Size\ &size\ :\ cfg.formats().sizes(format))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ \ \ std::cout\ <<\ \"\ \ ->\ supports\ size\ \"\ <<\ size\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\t\}\n\n\ \ \ \ \ \ \ \ Stream\ *stream\ =\ streamConfig.stream()\;\n\ \ \ \ \ \ \ \ assert(streamConfig.pixelFormat.toString()\ ==\ \"YUV420\")\;\n\n\ \ \ \ \ \ \ \ const\ std::vector<std::unique_ptr<FrameBuffer>>\ &buffers\ =\ allocator->buffers(stream)\;\n\tfor\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ buffers.size()\;\ ++i)\ \{\n\t\tstd::unique_ptr<Request>\ request\ =\ camera->createRequest()\;\n\t\tif\ (!request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ create\ request\")\;\n\t\t\}\n\n\t\tconst\ std::unique_ptr<FrameBuffer>\ &buffer\ =\ buffers\[i\]\;\n\t\tint\ ret\ =\ request->addBuffer(stream,\ buffer.get())\;\n\t\tif\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ set\ buffer\ for\ request\")\;\n\t\t\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ControlList\ &controls\ =\ request->controls()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AeEnable,\ false)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::ExposureTime,\ 35000)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AfMode,\ controls::AfModeManual)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Focus\ 30cm\ away\ (0.3m\ ->\ 1/0.3\ =\ 3.3).\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::LensPosition,\ 1.6)\;\n\n\t\trequests.push_back(std::move(request))\;\n\t\}\n\n\tcamera->requestCompleted.connect(requestComplete)\;\n\n\ \ \ \ \ \ \ \ camera->start()\;\n\tfor\ (std::unique_ptr<Request>\ &request\ :\ requests)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(request.get())\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (request->status()\ ==\ Request::RequestCancelled)\ \{\n\t\treturn\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.lock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.push(request)\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.unlock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsCv.notify_one()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ static\ void\ processRequestAndCopyFrame(Request\ *request,\ Image\ im)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ Request::BufferMap\ &buffers\ =\ request->buffers()\;\n\ \ \ \ \ \ \ \ \ \ \ \ assert(buffers.size()\ ==\ 1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (auto\ bufferPair\ :\ buffers)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ (Unused)\ Stream\ *stream\ =\ bufferPair.first\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FrameBuffer\ *buffer\ =\ bufferPair.second\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ FrameMetadata\ &metadata\ =\ buffer->metadata()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(metadata.planes().size()\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(buffer->planes().size()\ ==\ 3)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto\ &plane\ =\ buffer->planes()\[0\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ fd\ =\ plane.fd.get()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *addr\ =\ mmap64(NULL,\ plane.length,\ PROT_READ,\ MAP_PRIVATE,\ fd,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (addr\ ==\ MAP_FAILED)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ MAP_FAILED\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *planeData\ =\ (uint8_t\ *)addr\ +\ plane.offset\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(im.data,\ planeData,\ frameHeight\ *\ frameBytesPerRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ munmap(addr,\ plane.length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ newImage\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ uint32_t\ width\ =\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ height\ =\ frameHeight\;\n\ \ \ \ \ \ \ \ int\ components\ =\ 1\;\n\ \ \ \ \ \ \ \ uint8_t\ *data\ =\ (uint8_t\ *)\ malloc(width*components*height)\;\n\ \ \ \ \ \ \ \ return\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ components,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ width*components,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ freeImage\ \{Image\ image\}\ void\ \{\n\ \ \ \ \ \ \ \ free(image.data)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ grayFrame\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ Request\ *latestRequest\ =\ nullptr\;\n\n\ \ \ \ \ \ \ \ //\ We\ want\ to\ drain\ the\ queue\ of\ completed\ requests.\n\ \ \ \ \ \ \ \ std::unique_lock\ lk(completedRequestsMutex)\;\n\ \ \ \ \ \ \ \ completedRequestsCv.wait(lk,\ \[\]\{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ !completedRequests.empty()\;\n\ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ while\ (!completedRequests.empty())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (latestRequest\ !=\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ We're\ skipping\ this\ request,\ because\ we\ have\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ newer\ one\ in\ the\ queue.\ Requeue\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ latestRequest\ =\ completedRequests.front()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.pop()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lk.unlock()\;\n\n\ \ \ \ \ \ \ \ if\ (latestRequest\ ==\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"No\ new\ frame\ yet\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ newImage()\;\n\ \ \ \ \ \ \ \ processRequestAndCopyFrame(latestRequest,\ im)\;\n\n\ \ \ \ \ \ \ \ /*\ Re-queue\ the\ Request\ to\ the\ camera.\ */\n\ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ compile\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /cameraPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/decorations/label.folk is repla (
[ m780:0 (s1200:0) ]
[ m782:0 (s1203:0) ]
)when the collected results for {/any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/decorations/label.folk programCode {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
}
When /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk is rep (
[ m786:0 (s1210:0) ]
[ m788:0 (s1213:0) ]
)when the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/decorations/outline.folk programCode When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk is repl (
[ m792:0 (s1219:0) ]
[ m794:0 (s1222:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/editor/draw-editor.folk programCode When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk is rep (
[ m798:0 (s1228:0) ]
[ m800:0 (s1231:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/editor/editor-utils.folk programCode {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport {originalText x y width height} {
set lines [split $originalText \n]
set lines [lrange $lines $y [expr {($height - 1) + $y}]]
set lines [lmap line $lines {
set line [string range $line $x [expr {($width - 1) + $x}]]
}]
return [join $lines \n]
}
proc cursorToXy {code cursor} {
set codeBeforeCursor [string range $code 0 [- $cursor 1]]
set linesBeforeCursor [split $codeBeforeCursor "\n"]
set lineCountBeforeCursor [llength $linesBeforeCursor]
set cursorX [string length [lindex $linesBeforeCursor end]]
set cursorY [max [- $lineCountBeforeCursor 1] 0]
return [list $cursorX $cursorY]
}
proc xyToCursor {code cursorX cursorY} {
if { $cursorX < 0 } { set cursorX 0 }
if { $cursorY < 0 } { set cursorY 0 }
set lines [split $code "\n"]
set maxCursorY [max 0 [- [llength $lines] 1]]
set cursorY [min $cursorY $maxCursorY]
set relevantLines [lrange $lines 0 [- $cursorY 1]]
set relevantLineLen [string length [lindex $lines $cursorY]]
set joined [join $relevantLines "\n"]
# make sure cursorX < line length
set cursorX [min $cursorX $relevantLineLen]
set cursor [+ [string length $joined] $cursorX]
# don't forget to add the length of \n at the beginning
if {$cursorY > 0} { incr cursor }
return $cursor
}
proc insertText {code cursor newText} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code $cursor end]
set joined [join [list $before $newText $after] ""]
incr cursor
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $joined $cursor $maxCursorX]
}
proc deleteText {code cursor count} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code [+ $cursor $count] end]
set joined [join [list $before $after] ""]
return $joined
}
proc deleteToBeginning {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
set newLine [string range $line $x end]
lset lines $y $newLine
return [join $lines "\n"]
}
proc getLine {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
}
proc getLineLength {code cursor} {
set line [getLine $code $cursor]
set ll [string length $line]
return $ll
}
# returns {newCursor newMaxCursorX}
proc handleNavigation {key code cursor maxCursorX} {
switch $key {
Left {
set cursor [- $cursor 1]
set cursor [max $cursor 0]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Right {
set cursor [+ $cursor 1]
set codeLength [string length $code]
set cursor [min $cursor $codeLength]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Up {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [- $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Down {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [+ $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Control_a {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX 0
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
Control_e {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX [getLineLength $code $cursor]
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
}
return [list $cursor $maxCursorX]
}
# returns {newCode newCursor newMaxCursorX}
proc handleRemovalAndReturn {key code cursor maxCursorX} {
switch $key {
Delete {
if { $cursor != 0 } {
set cursor [- $cursor 1]
set code [deleteText $code $cursor 1]
set maxCursorX [lindex [cursorToXy $code $cursor] 0]
}
}
Remove {
set code [deleteText $code $cursor 1]
}
Control_u {
# delete from cursor back to 0 and move cursor to 0
lassign [cursorToXy $code $cursor] cursorX cursorY
set code [deleteToBeginning $code $cursor]
set newX 0
set cursor [xyToCursor $code $newX $cursorY]
}
Return {
# figure out how many spaces there are before the current line
regexp {^(\s*)} [getLine $code $cursor] -> spacing
set spacingLen [string length $spacing]
lassign [insertText $code $cursor "\n$spacing"] code
set maxCursorX $spacingLen
set cursor [+ $cursor [+ 1 $spacingLen]]
}
}
return [list $code $cursor $maxCursorX]
}
proc getSelectedText {code selAnchor cursor} {
set start [min $selAnchor $cursor]
set end [max $selAnchor $cursor]
return [string range $code $start [- $end 1]]
}
proc replaceRange {code rangeStart rangeEnd newText} {
if {$rangeStart > 0} {
set before [string range $code 0 [- $rangeStart 1]]
} else {
set before ""
}
set after [string range $code $rangeEnd end]
set code "${before}${newText}${after}"
set cursor [+ $rangeStart [string length $newText]]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $code $cursor $maxCursorX]
}
proc lineNumberView {ystart linecount} {
set yend [expr {$ystart + $linecount}]
set numbers [list]
for {set i [expr {$ystart + 1}]} {$i <= $yend} {incr i} {
lappend numbers $i
}
join $numbers "\n"
}
# For rendering:
proc getAdvance {em} {
# From NeomatrixCode.csv
return $(0.5859375 * $em)
}
proc widthAndHeight {resolvedGeom} {
set tagSize [dict get $resolvedGeom tagSize]
set left [dict get $resolvedGeom left]
set right [dict get $resolvedGeom right]
set top [dict get $resolvedGeom top]
set bottom [dict get $resolvedGeom bottom]
set width $($left + $tagSize + $right)
set height $($top + $tagSize + $bottom)
return [list $width $height]
}
# given program and the editor options, figure out how many characters can
# fit in this editor
proc editorSizeInCharacters {margin resolvedGeom options} {
set textScale [dict get $options scale]
set advance [getAdvance $textScale]
lassign [widthAndHeight $resolvedGeom] width height
set width $($width - [lindex $margin 3] - $advance*2.5 - [lindex $margin 1])
set height $($height - [lindex $margin 0] - [lindex $margin 2])
set widthInCharacters $(int($width / $advance))
set heightInCharacters $(int($height / $textScale))
return [list $widthInCharacters $heightInCharacters]
}
}]
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/editor.folk is replaced (
[ m805:0 (s1238:0) ]
[ m807:0 (s1241:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/editor/editor.folk programCode #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ later,\ or\ exclude\ keyboards\ that\ opt\ out.\nWhen\ /k/\ is\ a\ keyboard\ with\ /...opts/\ \{\n\ \ \ \ Wish\ tag\ \$k\ is\ stabilized\n\n\ \ \ \ When\ \$k\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ claims\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Create\ a\ synthetic\ editor\ on\ top\ of\ the\ program\ being\ edited,.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editor\ \[list\ \$k\ editor\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ is\ an\ editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ has\ a\ canvas\ with\ layer\ 98\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ has\ resolved\ geometry\ \$geom\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ quad\ /q/\ \{\ Claim\ \$editor\ has\ quad\ \$q\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ has\ created\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$editor\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$program\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ program\ save\ directory\ is\ /programDir/\ &\\\n\ \ \ \ \ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk is rep (
[ m811:0 (s1248:0) ]
[ m813:0 (s1251:0) ]
)when the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/editor/print-editor.folk programCode fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\}\n\nSubscribe:\ print\ program\ from\ editor\ /editor/\ \{\n\ \ \ \ set\ options\ \[editorToPrintOptions\ \$editor\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\n\n#\ Print\ preview:\nWhen\ the\ codeToPostScript\ is\ /codeToPostScript/\ &\\\n\ \ \ \ \ /someone/\ wishes\ editor\ /editor/\ has\ a\ print\ preview\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk is re (
[ m817:0 (s1258:0) ]
[ m819:0 (s1261:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/saving/save-programs.folk programCode When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/saving.folk is replaced (
[ m823:0 (s1267:0) ]
[ m825:0 (s1270:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/saving/saving.folk programCode set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\]\}\ \{\n\ \ \ \ file\ mkdir\ \$dataDirectory\n\}\n\n#\ make\ sure\ the\ migration\ happens\ before\ loading\ everything,\n#\ so\ we\ load\ in\ the\ migrated\ data\nWhen\ the\ migration\ is\ complete\ \{\n\ \ \ \ set\ namespaces\ \[glob\ -nocomplain\ \$dataDirectory/*/\]\n\n\ \ \ \ foreach\ namespace\ \$namespaces\ \{\n\ \ \ \ \ \ \ \ set\ namespaceName\ \[file\ tail\ \$namespace\]\n\ \ \ \ \ \ \ \ Wish\ to\ deserialize\ namespace\ \$namespaceName\ with\ directory\ \$namespace\n\ \ \ \ \}\n\}\n\nWhen\ when\ the\ /fileType/\ save\ directory\ is\ /anything/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ set\ serdeDirectory\ \"\$dataDirectory/\$fileType\"\n\n\ \ \ \ #\ make\ sure\ directory\ exists\n\ \ \ \ file\ mkdir\ \$serdeDirectory\n\n\ \ \ \ Claim\ the\ \$fileType\ save\ directory\ is\ \$serdeDirectory\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk is replaced (
[ m834:0 (s1287:0) ]
[ m836:0 (s1290:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/saving/migrate.folk programCode When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /programDirectory/\ &\\\n\ \ \ \ \ saving\ is\ ready\ \{\n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk is repla (
[ m844:0 (s1300:0) ]
[ m846:0 (s1303:0) ]
)when the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/saving/save-holds.folk programCode set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ \"jim.h\"\n\n\$cc\ code\ \{\n\n/*\ Generic\ string\ hash\ function\ from\ jim.c\ */\nstatic\ unsigned\ int\ cacheGenHashFunction(const\ unsigned\ char\ *string,\ int\ length)\ \{\n\ \ \ \ unsigned\ result\ =\ 0\;\n\ \ \ \ string\ +=\ length\;\n\ \ \ \ while\ (length--)\ \{\n\ \ \ \ \ \ \ \ result\ +=\ (result\ <<\ 3)\ +\ (unsigned\ char)(*--string)\;\n\ \ \ \ \}\n\ \ \ \ return\ result\;\n\}\nstatic\ unsigned\ int\ holdHTHashFunction(const\ void\ *key)\ \{\n\ \ \ \ return\ cacheGenHashFunction(key,\ strlen(key))\;\n\}\nstatic\ void\ *holdHTKeyDup(void\ *privdata,\ const\ void\ *key)\ \{\n\ \ \ \ return\ strdup(key)\;\n\}\nstatic\ void\ *holdHTValDup(void\ *privdata,\ const\ void\ *val)\ \{\n\ \ \ \ return\ strdup(val)\;\n\}\nstatic\ int\ holdHTKeyCompare(void\ *privdata,\ const\ void\ *key1,\ const\ void\ *key2)\ \{\n\ \ \ \ return\ strcmp(key1,\ key2)\ ==\ 0\;\n\}\nstatic\ void\ holdHTKeyDestructor(void\ *privdata,\ void\ *key)\ \{\n\ \ \ \ free(key)\;\n\}\nstatic\ void\ holdHTValDestructor(void\ *privdata,\ void\ *val)\ \{\n\ \ \ \ free(val)\;\n\}\n\nstatic\ const\ Jim_HashTableType\ holdHashTableType\ =\ \{\n\ \ \ \ .hashFunction\ =\ holdHTHashFunction,\n\ \ \ \ .keyDup\ =\ holdHTKeyDup,\n\ \ \ \ .valDup\ =\ holdHTValDup,\n\ \ \ \ .keyCompare\ =\ holdHTKeyCompare,\n\ \ \ \ .keyDestructor\ =\ holdHTKeyDestructor,\n\ \ \ \ .valDestructor\ =\ holdHTValDestructor\n\}\;\n\n//\ key\ =\ value\ of\ -on\ passed\ to\ Hold!,\n//\ val\ =\ string\ that\ can\ be\ converted\ to\ a\ jim\ dict,\ with\n//\ that\ dict\ having\ its\ key\ =\ the\ value\ passed\ to\ -key\n//\ and\ its\ value\ =\ its\ corresponding\ held\ statement\nstatic\ Jim_HashTable\ holds\;\nstatic\ int\ areHoldsInitialized\ =\ 0\;\n\nstatic\ pthread_mutex_t\ holdMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ if\ (!areHoldsInitialized)\ \{\n\ \ \ \ \ \ \ \ areHoldsInitialized\ =\ 1\;\n\ \ \ \ \ \ \ \ Jim_InitHashTable(&holds,\ &holdHashTableType,\ interp)\;\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n\$cc\ proc\ loadHolds\ \{char*\ canonicalName\ char*\ holdStr\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonicalName,\ (void\ *)holdStr)\;\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n#\ canonical,\ tclEscaped,\ and\ filename\ all\ have\ to\ do\ with\ the\ value\ from\ -on\ in\ Hold!\n\$cc\ proc\ saveHold\ \{char*\ canonical\ Jim_Obj*\ tclEscaped\ char*\ filename\ Jim_Obj*\ key\ Jim_Obj*\ clause\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ assert(areHoldsInitialized)\;\n\n\ \ \ \ Jim_Obj*\ holdDict\ =\ NULL\;\n\n\ \ \ \ Jim_HashEntry*\ he\ =\ Jim_FindHashEntry(&holds,\ canonical)\;\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ //\ this\ is\ this\ files'\ first\ hold\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewStringObj(interp,\ (char\ *)Jim_GetHashEntryVal(he),\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ empty\ clause,\ e.g.\ removal\n\ \ \ \ if\ (Jim_Length(clause)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ NULL)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ clause)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonical,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_SetHashVal(&holds,\ he,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\n\ \ \ \ //\ grab\ entries\ from\ dict\n\ \ \ \ int\ dictLen\ =\ 0\;\n\ \ \ \ Jim_Obj**\ dictValues\ =\ Jim_DictPairs(interp,\ holdDict,\ &dictLen)\;\n\n\ \ \ \ if\ (dictLen\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ //\ write\ changes\n\ \ \ \ \ \ \ \ FILE*\ file\ =\ fopen(filename,\ \"w+b\")\;\n\ \ \ \ \ \ \ \ assert(file\ !=\ NULL)\;\n\n\ \ \ \ \ \ \ \ //\ write\ the\ filename\ in\ tcl\ form\ at\ the\ top\ of\ the\ file\n\ \ \ \ \ \ \ \ fwrite(Jim_String(tclEscaped),\ 1,\ Jim_Length(tclEscaped),\ file)\;\n\ \ \ \ \ \ \ \ fwrite(\"\\n\\n\",\ 1,\ 2,\ file)\;\n\n\ \ \ \ \ \ \ \ //\ write\ all\ hash\ entries,\ with\ one\ entry\ per\ line\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ dictLen\;\ i\ +=\ 2)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ pair\[\]\ =\ \{\ dictValues\[i\],\ dictValues\[i\ +\ 1\]\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ tmpListObj\ =\ Jim_NewListObj(interp,\ pair,\ 2)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(Jim_String(tmpListObj),\ 1,\ Jim_Length(tmpListObj),\ file)\;\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(\"\\n\",\ 1,\ 1,\ file)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_FreeNewObj(interp,\ tmpListObj)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ fclose(file)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ //\ the\ dict\ is\ empty,\ so\ we\ should\ delete\ its\ hold\ file\ if\ it\ exists\n\ \ \ \ \ \ \ \ remove(filename)\;\ //\ no\ need\ to\ check\ error\n\ \ \ \ \}\n\n\ \ \ \ Jim_FreeNewObj(interp,\ holdDict)\;\n\}\n\nset\ savedHoldsLib\ \[\$cc\ compile\]\n\$savedHoldsLib\ init\n\nWhen\ /someone/\ wishes\ to\ deserialize\ namespace\ hold\ with\ directory\ /directory/\ \{\n\ \ \ \ set\ holdFiles\ \[glob\ -nocomplain\ \$directory/*\]\n\n\ \ \ \ foreach\ holdFile\ \$holdFiles\ \{\n\ \ \ \ \ \ \ \ set\ fd\ \[open\ \$holdFile\ r\]\n\ \ \ \ \ \ \ \ set\ holds\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ #\ the\ hold\ file's\ first\ line\ is\ its\ canonical\ name\ (since\n\ \ \ \ \ \ \ \ #\ having\ /\ in\ a\ filename\ would\ mess\ a\ lot\ of\ stuff\ up),\n\ \ \ \ \ \ \ \ #\ while\ the\ rest\ of\ the\ file\ is\ a\ dict\ of\ holds\n\ \ \ \ \ \ \ \ set\ canonicalName\ \[lindex\ \$holds\ 0\]\n\ \ \ \ \ \ \ \ set\ holdDict\ \[lrange\ \$holds\ 1\ end\]\n\n\ \ \ \ \ \ \ \ dict\ for\ \{key\ clause\}\ \$holdDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ \$canonicalName\ -key\ \$key\ --\ \{*\}\$clause\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ loadHolds\ \$canonicalName\ \$holdDict\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ saved\ holds\ are\ loaded\n\}\n\nWhen\ the\ hold\ save\ directory\ is\ /holdDirectory/\ \{\n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced wi (
[ m852:0 (s1311:0) ]
[ m854:0 (s1314:0) ]
)when the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/gpu/gpu-fns.folk programCode {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
Wish the GPU compiles function "wedge2d" {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
# See https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/
Wish the GPU compiles function "invBilinear" {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/shapes/region.folk is replaced (
[ m858:0 (s1322:0) ]
[ m860:0 (s1325:0) ]
)when the collected results for {/any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/shapes/region.folk programCode #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ used\ to\ create\ sensitive\ areas\ other\ pages\ can\ collect.\nWhen\ /someone/\ wishes\ /p/\ adds\ region\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ region\ /r/\ has\ highlight\ /highlighted/\ with\ /...options/\ \{\n\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\n\ \ if\ \{\$highlighted\}\ \{\n\ \ \ \ set\ verts\ \[region\ vertices\ \$r\]\n\ \ \ \ set\ edges\ \[region\ edges\ \$r\]\n\ \ \ \ lappend\ verts\ \[lindex\ \$verts\ 0\]\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$verts\ color\ \$color\ width\ \$thickness\ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/display/arc.folk is replaced wi (
[ m864:0 (s1333:0) ]
[ m866:0 (s1336:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/display/arc.folk programCode #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n#\ \ \ \ \ Wish\ to\ draw\ an\ arc\ with\ x\ \$x\ y\ \$y\ start\ 0\ arclen\ 1\ thickness\ 3\ radius\ 100\ color\ green\n#\ \ \ \}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"arc\"\ \{\{vec2\ center\ float\ start\ float\ arclen\ float\ radius\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\ \ \ \ \ \ \ \ \ center\ +\ r\n\ \ \ \ )\;\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\}\ \{\n\ \ \ \ #define\ M_TWO_PI\ 6.283185307179586\n\ \ \ \ start\ =\ clamp(start,\ 0,\ M_TWO_PI)\;\n\ \ \ \ arclen\ =\ clamp(arclen,\ 0,\ M_TWO_PI)\;\n\n\ \ \ \ float\ dist\ =\ length(gl_FragCoord.xy\ -\ center)\ -\ radius\;\n\ \ \ \ float\ angle\ =\ atan(-(gl_FragCoord.y\ -\ center.y),\ gl_FragCoord.x\ -\ center.x)\;\n\n\ \ \ \ //\ Shift\ angle\ from\ \[-pi,\ pi)\ to\ \[0,\ 2*pi\]\n\ \ \ \ angle\ =\ (angle\ <\ 0)\ ?\ (angle\ +\ M_TWO_PI)\ :\ angle\;\n\ \ \ \ float\ end\ =\ start\ +\ arclen\;\n\n\ \ \ \ return\ ((dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((end\ <\ M_TWO_PI\ &&\ angle\ >\ start\ &&\ angle\ <\ end)\ ||\ \n\ \ \ \ \ \ \ \ \ \ \ \ (end\ >=\ M_TWO_PI\ &&\ (angle\ >\ start\ ||\ angle\ <\ end-M_TWO_PI))))\ ?\ color\ :\ vec4(0,\ 0,\ 0,\ 0)\;\n\n\}\}\n\nWhen\ /someone/\ wishes\ to\ draw\ an\ arc\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/display/curve.folk is replaced (
[ m870:0 (s1343:0) ]
[ m872:0 (s1346:0) ]
)when the collected results for {/any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/display/curve.folk programCode \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ compiles\ function\ \"bboxBezier\"\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\}\ vec4\ \{\n\ \ \ \ //\ Exact\ BBox\ to\ a\ quadratic\ bezier\n\ \ \ \ //\ extremes\n\ \ \ \ vec2\ mi\ =\ min(p0,p3)\;\n\ \ \ \ vec2\ ma\ =\ max(p0,p3)\;\n\n\ \ \ \ vec2\ k0\ =\ -1.0*p0\ +\ 1.0*p1\;\n\ \ \ \ vec2\ k1\ =\ \ 1.0*p0\ -\ 2.0*p1\ +\ 1.0*p2\;\n\ \ \ \ vec2\ k2\ =\ -1.0*p0\ +\ 3.0*p1\ -\ 3.0*p2\ +\ 1.0*p3\;\n\n\ \ \ \ vec2\ h\ =\ k1*k1\ -\ k0*k2\;\n\n\ \ \ \ if(\ h.x>0.0\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.x\ =\ sqrt(h.x)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.x\ -\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.x/(-k1.x-h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.x\ +\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ t\ =\ k0.x/(-k1.x+h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if(\ h.y>0.0)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.y\ =\ sqrt(h.y)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.y\ -\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.y/(-k1.y-h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.y\ +\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ t\ =\ k0.y/(-k1.y+h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \n\ \ \ \ return\ vec4(\ mi,\ ma\ )\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ sdSegmentSq\ \{\{vec2\ p\ vec2\ a\ vec2\ b\}\ float\ \{\n\ \ \ \ vec2\ pa\ =\ p-a,\ ba\ =\ b-a\;\n\ \ \ \ float\ h\ =\ clamp(\ dot(pa,ba)/dot(ba,ba),\ 0.0,\ 1.0\ )\;\n\ \ \ \ vec2\ d\ =\ pa\ -\ ba*h\;\n\ \ \ \ return\ dot(d,\ d)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ udBezier\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ vec2\ pos\}\ vec2\ \{\n\ \ \ \ const\ int\ kNum\ =\ 50\;\n\ \ \ \ vec2\ res\ =\ vec2(1e10,0.0)\;\n\ \ \ \ vec2\ a\ =\ p0\;\n\ \ \ \ for(\ int\ i=1\;\ i<kNum\;\ i++\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ float\ t\ =\ float(i)/float(kNum-1)\;\n\ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ vec2\ b\ =\ p0*s*s*s\ +\ p1*3.0*s*s*t\ +\ p2*3.0*s*t*t\ +\ p3*t*t*t\;\n\ \ \ \ \ \ \ \ float\ d\ =\ sdSegmentSq(\ pos,\ a,\ b\ )\;\n\ \ \ \ \ \ \ \ if(\ d<res.x\ )\ res\ =\ vec2(d,t)\;\n\ \ \ \ \ \ \ \ a\ =\ b\;\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ vec2(sqrt(res.x),res.y)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"curve\"\ \{\n\ \ \{\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ //\ Need\ to\ calculate\ the\ bounds\ of\ the\ curve\n\ \ \ \ vec2\ from\ =\ min(min(p0,p1),min(p2,p3))\;\n\ \ \ \ vec2\ to\ =\ max(max(p0,p1),max(p2,p3))\;\n\ \ \ \ \n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ min(from,\ to)\ -\ thickness,\n\ \ \ \ \ \ vec2(max(from.x,\ to.x)\ +\ thickness,\ min(from.y,\ to.y)\ -\ thickness),\n\ \ \ \ \ \ vec2(min(from.x,\ to.x)\ -\ thickness,\ max(from.y,\ to.y)\ +\ thickness),\n\ \ \ \ \ \ max(from,\ to)\ +\ thickness\n\ \ \ \ )\;\n\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\ \ \}\ \{fn\ sdSegmentSq\ fn\ udBezier\}\ \{\n\ \ \ \ vec2\ p\ =\ gl_FragCoord.xy\;\n\ \ \ \ float\ px\ =\ 2.0\;\ //\ sharpness\n\ \ \ \ float\ t\ =\ thickness\;\n\ \ \ \ float\ be\ =\ udBezier(\ p0,\ p1,\ p2,\ p3,\ p\ ).x\;\n\n\ \ \ \ float\ d\ =\ be\;\n\n\ \ \ \ vec4\ col\ =\ mix(\ vec4(0.0),\ color,\ 1.0-smoothstep(t,\ t\ +\ px*1.5,\ d)\ )\;\n\n\ \ \ \ //\ control\ points\n\ \ \ \ //d\ =\ length(p0-p)\;\ col\ =\ mix(\ col,\ vec4(1.0,\ 0.,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p1-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 1.0,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p2-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 0.,\ 1.0,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p3-p)\;\ col\ =\ mix(\ col,\ vec4(1.0),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\n\ \ \ \ return\ col\;\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ curve\ with\ /...options/\ \{\n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk is repla (
[ m876:0 (s1356:0) ]
[ m878:0 (s1359:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/recognition/trocr.folk programCode When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ TrOCR\ text\ recognizer\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ TrOCR\ text\ recognizer\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ transformers\ --with\ pillow\ --with\ torch\ --with\ protobuf\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ from\ transformers\ import\ TrOCRProcessor,\ VisionEncoderDecoderModel\n\ \ \ \ \ \ \ \ import\ os\n\ \ \ \ \ \ \ \ import\ sys\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ #\ Determine\ device\ (prefer\ CUDA\ >\ MPS\ >\ CPU)\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ #\ Load\ TrOCR\ model\n\ \ \ \ \ \ \ \ TROCR_PATH\ =\ os.path.expanduser(\"~/folk-data/trocr\")\n\ \ \ \ \ \ \ \ try:\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ disk.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ except\ Exception:\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Model\ not\ saved\;\ loading\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ processor.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ model.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ model.to(device)\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ ocrImage\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ start_time\ =\ time.time()\n\n\ \ \ \ \ \ \ \ #\ Run\ TrOCR\ on\ the\ entire\ image\n\ \ \ \ \ \ \ \ with\ torch.no_grad():\n\ \ \ \ \ \ \ \ \ \ \ \ pixel_values\ =\ processor(image,\ return_tensors=\"pt\").pixel_values.to(device)\n\ \ \ \ \ \ \ \ \ \ \ \ generated_ids\ =\ model.generate(pixel_values)\n\ \ \ \ \ \ \ \ \ \ \ \ text\ =\ processor.batch_decode(generated_ids,\ skip_special_tokens=True)\[0\]\n\n\ \ \ \ \ \ \ \ elapsed\ =\ time.time()\ -\ start_time\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Result:\ \{text\}\ (\{elapsed:.3f\}s)\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ return\ text\n\ \ \ \ \}\n\n\ \ \ \ fn\ TrOCR\ \{im\}\ \{\ return\ \[\$py\ ocrImage\ \$im\]\ \}\n\ \ \ \ Claim\ the\ TrOCR\ text\ recognizer\ is\ \[fn\ TrOCR\]\n\}\n\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk is replac (
[ m882:0 (s1366:0) ]
[ m884:0 (s1369:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/recognition/sam2.folk programCode When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ SAM2\ segmenter\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ SAM2\ segmenter\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n\}\n\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk is repla (
[ m888:0 (s1376:0) ]
[ m890:0 (s1379:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/recognition/craft.folk programCode When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ CRAFT\ text\ detector\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ CRAFT\ text\ detector\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ \"git+https://github.com/osnr/craft-text-detector.git\"\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ from\ craft_text_detector\ import\ Craft\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ craft\ =\ Craft(output_dir=None,\ crop_type=\"box\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ link_threshold=0.1,\ device=device)\n\ \ \ \ \}\n\ \ \ \ \$py\ def\ detectTextBoxes\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image)\n\n\ \ \ \ \ \ \ \ start_craft\ =\ time.time()\n\ \ \ \ \ \ \ \ result\ =\ craft.detect_text(image_np)\n\ \ \ \ \ \ \ \ boxes\ =\ result\[\"boxes\"\]\n\ \ \ \ \ \ \ \ craft_time\ =\ time.time()\ -\ start_craft\n\n\ \ \ \ \ \ \ \ print(f\"craft:\ Detected\ \{len(boxes)\}\ text\ boxes\ (\{craft_time:.3f\}s)\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ return\ boxes.tolist()\ if\ hasattr(boxes,\ 'tolist')\ else\ boxes\n\ \ \ \ \}\n\n\ \ \ \ fn\ CRAFT\ \{im\}\ \{\ return\ \[\$py\ detectTextBoxes\ \$im\]\ \}\n\ \ \ \ Claim\ the\ CRAFT\ text\ detector\ is\ \[fn\ CRAFT\]\n\}\n\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk is re (
[ m894:0 (s1386:0) ]
[ m896:0 (s1389:0) ]
)when the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this builtin-programs/recognition/contours.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ cflags\ -I.\n\ \ \ \ \$cc\ include\ \"vendor/CContour.c\"\n\n\ \ \ \ #\ Binarizes\ the\ first\ channel\ of\ `im`\ at\ `threshold`\ and\ returns\n\ \ \ \ #\ the\ contours\ as\ a\ Tcl\ list.\ Each\ contour\ is\ itself\ a\ Tcl\ list\ of\n\ \ \ \ #\ \{x\ y\}\ pairs.\ If\ epsilon\ >\ 0,\ each\ contour\ is\ simplified\ with\n\ \ \ \ #\ Ramer-Douglas-Peucker.\n\ \ \ \ #\n\ \ \ \ #\ Contours\ are\ scaled\ by\ `scaleX`\ and\ `scaleY`\ so\ that\ they\ can\ be\n\ \ \ \ #\ returned\ in\ real-world\ meters\ (instead\ of\ image-pixel\ space).\n\ \ \ \ #\n\ \ \ \ #\ Discards\ any\ contours\ that\ are\ not\ at\ least\ minLength\ long\n\ \ \ \ #\ (unless\ minLength\ is\ very\ small).\n\ \ \ \ \$cc\ proc\ findImageContours\ \{Image\ im\ int\ threshold\ double\ epsilon\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ scaleX\ double\ scaleY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ minLength\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ w\ =\ (int)im.width\;\n\ \ \ \ \ \ \ \ int\ h\ =\ (int)im.height\;\n\ \ \ \ \ \ \ \ if\ (w\ <\ 3\ ||\ h\ <\ 3)\ return\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ int\ *F\ =\ malloc(sizeof(int)\ *\ (size_t)w\ *\ (size_t)h)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ h\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ *row\ =\ im.data\ +\ (size_t)y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ *Frow\ =\ F\ +\ (size_t)y\ *\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ w\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Frow\[x\]\ =\ (row\[x\ *\ im.components\]\ >\ threshold)\ ?\ 1\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Contour\ *contours\ =\ findContours(F,\ w,\ h)\;\n\ \ \ \ \ \ \ \ free(F)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj\ *outer\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (ptrdiff_t\ c\ =\ 0\;\ c\ <\ arrlen(contours)\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Point\ *pts\ =\ (epsilon\ >\ 0)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ?\ approxPolyDP(contours\[c\].points,\ (float)epsilon)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :\ contours\[c\].points\;\n\ \ \ \ \ \ \ \ \ \ \ \ ptrdiff_t\ n\ =\ arrlen(pts)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (minLength\ >\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ total\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 1\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ (pts\[k\].x\ -\ pts\[k-1\].x)\ *\ scaleX\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ (pts\[k\].y\ -\ pts\[k-1\].y)\ *\ scaleY\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (total\ <\ minLength)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ %g\ prints\ up\ to\ ~13\ chars\ per\ double\;\ round\ up\ to\ give\ headroom.\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ cap\ =\ (size_t)n\ *\ 40\ +\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ char\ *buf\ =\ malloc(cap)\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ off\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 0\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ off\ +=\ snprintf(buf\ +\ off,\ cap\ -\ off,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\ ==\ 0\ ?\ \"\{%g\ %g\}\"\ :\ \"\ \{%g\ %g\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pts\[k\].x\ *\ scaleX,\ pts\[k\].y\ *\ scaleY)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Jim_NewStringObjNoAlloc\ takes\ ownership\ of\ buf.\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ outer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObjNoAlloc(interp,\ buf,\ (int)off))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ freeContours(contours)\;\n\ \ \ \ \ \ \ \ return\ outer\;\n\ \ \ \ \}\n\n\ \ \ \ set\ contourLib\ \[\$cc\ compile\]\n\ \ \ \ Claim\ the\ contour\ library\ is\ \$contourLib\n\}\n\nWhen\ /someone/\ wishes\ /p/\ has\ contours\ \{\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ _\ \{\}\n\}\nWhen\ the\ contour\ library\ is\ /contourLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ contours\ with\ /...opts/\ \{\n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} are (
[ m1025:0 (s1800:0) ]
[ m1032:0 (s1812:0) ]
)when the collected results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} are /__results/ {if {[llength $__results] == 0} {When -serially camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n}} with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13}}
when the collected results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} are (
[ m1028:0 (s1807:0) ]
[ m1033:0 (s1800:0) ]
)when the collected results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} are /__results/ {if {[llength $__results] == 0} {When the image library is /imageLib/ & -serially camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n}} with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13}}
when the collected results for {/someone/ detects tags /tags/ on camera /camera/ at timestamp /timest (
[ m1027:0 (s1805:0) ]
[ m23155:1067 () ]
[ m23340:1067 () ]
[ m23392:1045 () ]
[ m23791:1063 () ]
[ m23908:1067 () ]
[ m23924:1067 () ]
[ m24104:1066 (s5279:1266 s5280:1266 s5282:1265 s5283:1258 s5284:1266 s5285:1266) ]
)when the collected results for {/someone/ detects tags /tags/ on camera /camera/ at timestamp /timestamp/ in time /aprilTime/} are /results/ \n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13}}
when the collected results for {/any/ claims a calibration from camera /camera/ to display /display/ (
[ m1063:0 (s1851:0) ]
[ m1065:0 () ]
)when the collected results for {/any/ claims a calibration from camera /camera/ to display /display/ is /anything/} are /__results/ {if {[llength $__results] == 0} {
Claim the calibration report is $posesReport
}} with environment {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 display monitor calibrationPoses {{model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 28 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-75314.698413 4478.401730 19997.029253 }{-971.492484 -71792.210770 22876.355728 }{-1.407849 2.419020 18.216270 }} rmse 0.725728225238 tags {48601 {id 48601 c {1385.029589 373.397601} p {{1367.431885 391.921936} {1405.210205 389.762604} {1402.768921 354.724182} {1364.972778 357.132996}} size 37 angle 0.057096} 48603 {id 48603 c {1538.393435 364.163451} p {{1520.251709 382.996368} {1560.268555 380.483032} {1556.391846 345.479309} {1516.824951 348.072632}} size 40 angle 0.062725} 48604 {id 48604 c {1314.707595 447.429039} p {{1296.983887 465.832520} {1334.821533 464.710083} {1332.746704 428.698059} {1294.883911 430.397369}} size 37 angle 0.029656} 48606 {id 48606 c {1466.610059 439.916687} p {{1448.426758 459.265656} {1487.840576 457.079193} {1484.453857 420.928986} {1445.619263 422.947968}} size 39 angle 0.055418} 48609 {id 48609 c {1394.987112 514.999554} p {{1377.006226 533.712585} {1415.902588 532.740601} {1413.313599 495.926849} {1374.507446 497.628174}} size 38 angle 0.024984} 48611 {id 48611 c {1551.315859 508.245212} p {{1533.442505 527.498169} {1572.451660 526.567932} {1569.045044 489.147552} {1530.549683 490.242920}} size 39 angle 0.023842} 48612 {id 48612 c {1323.958123 589.924482} p {{1306.240601 608.614990} {1344.435791 607.666931} {1341.827026 571.074280} {1303.762695 572.426575}} size 38 angle 0.024816} 48614 {id 48614 c {1479.024930 584.982536} p {{1460.857666 603.967041} {1500.821045 602.853821} {1497.578369 565.594482} {1457.400269 567.251831}} size 39 angle 0.027849} 48617 {id 48617 c {1406.285006 661.290040} p {{1388.146118 680.364746} {1427.638062 679.629700} {1424.388550 642.252502} {1385.154663 643.141663}} size 39 angle 0.018610} 48619 {id 48619 c {1565.543612 657.303678} p {{1547.084473 676.826904} {1587.975098 675.831177} {1583.959351 637.826355} {1543.498535 639.095337}} size 40 angle 0.024346} 48600 {id 48600 c {1311.069046 378.239945} p {{1293.403809 397.174408} {1331.194946 394.612976} {1328.710938 359.330505} {1291.372437 362.216156}} size 37 angle 0.067675} 48602 {id 48602 c {1460.901364 369.680924} p {{1443.130371 388.178741} {1482.119629 386.910889} {1479.017700 350.823639} {1440.809570 353.365692}} size 39 angle 0.032507} 48605 {id 48605 c {1390.772515 444.293298} p {{1372.398560 463.838928} {1411.644775 461.251099} {1408.589966 425.339661} {1369.880737 427.319641}} size 39 angle 0.065843} 48607 {id 48607 c {1544.826101 436.656867} p {{1526.837891 455.811432} {1566.585449 454.317230} {1563.773438 416.480988} {1523.533813 419.375580}} size 39 angle 0.037575} 48608 {id 48608 c {1320.136780 518.359033} p {{1302.109009 537.349243} {1340.637085 535.987244} {1338.151733 499.382324} {1299.486084 500.601501}} size 38 angle 0.035336} 48610 {id 48610 c {1472.920554 512.574182} p {{1454.544067 531.717834} {1494.853027 530.374573} {1491.634033 493.079468} {1451.511475 495.198578}} size 40 angle 0.033312} 48613 {id 48613 c {1401.442760 587.735040} p {{1383.686401 606.712585} {1422.481323 605.905945} {1419.349243 568.597046} {1380.474243 569.624634}} size 38 angle 0.020789} 48615 {id 48615 c {1558.880689 582.530694} p {{1540.743286 601.986816} {1580.547241 600.764343} {1576.885620 563.216675} {1537.027832 564.140259}} size 39 angle 0.030703} 48616 {id 48616 c {1329.655113 663.051861} p {{1311.354126 682.407532} {1350.495972 681.459778} {1347.780396 643.882019} {1309.224487 645.006287}} size 39 angle 0.024209} 48618 {id 48618 c {1486.141093 659.716024} p {{1467.177856 679.632935} {1507.811157 677.993408} {1504.760864 640.159851} {1464.393188 641.372986}} size 40 angle 0.040327}} imageName pose-1781543257841-0.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 43 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1056840.114219 42808.811083 264863.141447 }{32312.866960 -1007364.955709 402770.605979 }{-11.182218 42.695320 245.704300 }} rmse 1.89131853376 tags {48601 {id 48601 c {1395.952641 212.861420} p {{1377.588257 233.639587} {1417.538696 229.658676} {1414.197876 192.218063} {1374.617188 196.259171}} size 40 angle 0.099318} 48603 {id 48603 c {1553.635336 197.600660} p {{1535.305908 218.149307} {1575.980347 214.534927} {1571.934326 177.086136} {1531.557007 180.868500}} size 40 angle 0.088628} 48604 {id 48604 c {1324.137968 293.707576} p {{1306.116943 313.840912} {1345.083008 310.326050} {1341.587646 274.212555} {1303.338867 277.204895}} size 39 angle 0.089960} 48606 {id 48606 c {1480.843873 279.367657} p {{1462.405518 299.948456} {1502.627686 296.394623} {1499.185791 258.894501} {1459.289917 262.520355}} size 40 angle 0.088126} 48609 {id 48609 c {1408.072088 360.901788} p {{1390.102661 380.931671} {1429.527344 377.933807} {1426.243774 340.646454} {1386.851929 344.056396}} size 39 angle 0.075894} 48611 {id 48611 c {1567.259040 347.361196} p {{1549.179443 367.838379} {1588.584595 365.235809} {1584.650513 327.663391} {1546.489990 329.953033}} size 39 angle 0.065951} 48612 {id 48612 c {1336.656619 441.631250} p {{1318.508179 462.043243} {1358.458130 459.201569} {1354.721069 421.313721} {1315.223755 424.358032}} size 40 angle 0.071011} 48614 {id 48614 c {1494.646192 429.683558} p {{1476.802612 449.946777} {1516.712524 447.297180} {1512.817993 409.047607} {1472.774170 412.225037}} size 39 angle 0.066292} 48617 {id 48617 c {1423.249643 510.798629} p {{1404.714844 531.413879} {1445.430786 528.574585} {1441.903687 490.050751} {1400.936401 492.916809}} size 40 angle 0.069622} 48619 {id 48619 c {1583.746862 499.650259} p {{1566.048706 520.226074} {1606.481323 517.599731} {1601.709229 478.767273} {1560.927002 481.633362}} size 40 angle 0.064865} 48600 {id 48600 c {1318.372902 222.551387} p {{1299.982056 243.184250} {1339.737549 239.225800} {1336.857300 201.813568} {1296.936279 205.820801}} size 39 angle 0.099243} 48602 {id 48602 c {1474.613028 207.413025} p {{1456.190552 227.932159} {1496.754761 224.579254} {1493.370117 186.521194} {1452.811646 190.510666}} size 40 angle 0.082469} 48605 {id 48605 c {1402.289206 288.773703} p {{1381.081299 272.196045} {1383.976074 309.481049} {1423.905273 305.670410} {1420.299072 268.409271}} size 37 angle -1.493313} 48607 {id 48607 c {1560.824988 274.287257} p {{1542.879883 294.537292} {1582.193848 292.009033} {1578.751343 254.058380} {1539.623535 256.704315}} size 39 angle 0.064221} 48608 {id 48608 c {1330.693159 369.828011} p {{1312.406006 390.445038} {1352.469727 386.978882} {1349.092041 349.085022} {1309.401855 353.059326}} size 40 angle 0.086301} 48610 {id 48610 c {1488.474183 356.547666} p {{1469.599854 377.690796} {1510.819702 373.957123} {1506.693237 336.138580} {1466.973022 339.796051}} size 41 angle 0.090333} 48613 {id 48613 c {1416.229342 437.995789} p {{1394.115112 420.463196} {1397.874268 459.000122} {1438.656128 455.776184} {1434.263916 417.358215}} size 38 angle -1.473557} 48615 {id 48615 c {1575.955360 426.006059} p {{1557.106689 447.186432} {1598.870117 444.503754} {1594.429932 405.246063} {1553.894043 408.197296}} size 41 angle 0.064147} 48616 {id 48616 c {1344.023531 519.212660} p {{1325.910889 539.723450} {1366.120361 537.195007} {1362.370117 498.436951} {1322.228394 501.475830}} size 40 angle 0.062799} 48618 {id 48618 c {1504.497483 507.714315} p {{1485.648682 528.901550} {1527.599365 526.065979} {1523.404175 486.462006} {1481.829468 489.707306}} size 42 angle 0.067490}} imageName pose-1781543257841-1.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 64 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-209693.666866 32261.725933 45616.235897 }{9716.750647 -182727.705443 69957.706876 }{1.369661 20.418735 41.956332 }} rmse 1.12427806234 tags {48601 {id 48601 c {1509.711328 54.434227} p {{1480.648926 85.984230} {1536.133667 82.819717} {1538.859497 22.791117} {1483.493286 26.268213}} size 55 angle 0.056972} 48604 {id 48604 c {1394.354083 178.405525} p {{1365.312988 209.825806} {1421.084839 206.090240} {1423.003174 147.409363} {1367.770142 150.872864}} size 55 angle 0.066880} 48606 {id 48606 c {1610.914251 165.377982} p {{1581.291260 195.974930} {1636.133911 193.269714} {1640.511963 134.807144} {1585.921265 137.736938}} size 54 angle 0.049287} 48609 {id 48609 c {1495.829713 283.255061} p {{1467.725464 311.925690} {1520.545898 308.731995} {1524.365112 254.144592} {1470.828369 257.484192}} size 52 angle 0.060390} 48611 {id 48611 c {1706.065596 270.965025} p {{1678.112183 299.655853} {1728.069824 296.962830} {1733.845215 242.452576} {1684.113159 245.028412}} size 50 angle 0.053854} 48612 {id 48612 c {1385.763556 396.781625} p {{1358.841064 424.564758} {1411.064087 421.179443} {1412.717529 368.966003} {1360.271606 372.199219}} size 52 angle 0.064734} 48614 {id 48614 c {1592.767882 384.014632} p {{1565.013916 411.650513} {1615.941650 408.255951} {1620.917480 355.984802} {1568.793213 358.935516}} size 51 angle 0.066556} 48617 {id 48617 c {1484.082987 492.101955} p {{1456.933105 518.884766} {1508.521606 515.551514} {1511.408203 465.146179} {1459.290771 468.313110}} size 51 angle 0.064523} 48619 {id 48619 c {1684.106845 479.581249} p {{1656.806152 506.011230} {1707.054565 503.155701} {1711.697510 452.870544} {1661.051270 455.895996}} size 50 angle 0.056767} 48600 {id 48600 c {1399.789822 59.409994} p {{1369.518433 92.648804} {1426.722534 87.997520} {1428.329834 28.072285} {1372.388428 30.324989}} size 57 angle 0.081132} 48602 {id 48602 c {1620.425256 46.876868} p {{1590.636230 78.148476} {1645.181152 75.500832} {1650.330200 15.483572} {1595.297729 17.823208}} size 54 angle 0.048503} 48605 {id 48605 c {1502.972095 171.263498} p {{1473.294922 202.666061} {1529.038208 199.092056} {1532.439453 140.082947} {1476.357422 142.849289}} size 55 angle 0.064028} 48607 {id 48607 c {1716.798563 158.749720} p {{1687.903442 188.728394} {1740.135620 186.814194} {1747.215942 127.191704} {1692.823486 129.917984}} size 52 angle 0.036632} 48608 {id 48608 c {1389.683476 289.345012} p {{1361.929688 318.369263} {1415.511719 314.445282} {1418.558594 259.148102} {1363.436646 263.837952}} size 53 angle 0.073103} 48610 {id 48610 c {1601.362012 276.392144} p {{1572.501587 305.586060} {1625.155640 301.927612} {1630.324951 247.094528} {1577.106812 250.361313}} size 52 angle 0.069369} 48613 {id 48613 c {1489.824889 389.421889} p {{1462.307617 417.067352} {1514.499268 414.530518} {1517.472290 361.645691} {1465.068970 364.230286}} size 52 angle 0.048568} 48615 {id 48615 c {1694.785648 376.578606} p {{1666.799194 404.401581} {1716.849487 401.537170} {1721.927124 349.595673} {1672.444946 351.306854}} size 50 angle 0.057168} 48616 {id 48616 c {1381.972820 497.565982} p {{1355.683105 523.804565} {1407.246094 521.063721} {1409.440552 470.151672} {1356.126343 473.535309}} size 51 angle 0.053105} 48618 {id 48618 c {1585.154532 484.068682} p {{1557.027588 511.571320} {1609.122559 507.884888} {1612.781616 457.054810} {1561.358398 460.423279}} size 52 angle 0.070646}} imageName pose-1781543257841-2.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 84 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{98796.033601 -6946652.610637 2196614.745495 }{6739896.207720 460527.950943 1149462.297906 }{-190.312892 -80.550321 1480.650980 }} rmse 1.96923416025 tags {48601 {id 48601 c {1194.241663 327.654893} p {{1222.111084 348.784912} {1216.369019 300.245178} {1166.462280 306.593140} {1172.062500 355.128784}} size 48 angle 1.688545} 48603 {id 48603 c {1171.725758 137.153038} p {{1199.847046 158.204208} {1193.673950 110.035004} {1143.998901 116.397133} {1149.260986 164.909332}} size 48 angle 1.698256} 48604 {id 48604 c {1308.752097 412.254488} p {{1338.622192 434.530487} {1331.861450 384.154022} {1279.358032 390.333496} {1285.766602 440.204346}} size 50 angle 1.704204} 48606 {id 48606 c {1282.569227 218.915396} p {{1311.468262 240.157288} {1305.318115 190.902405} {1253.950073 197.879227} {1260.240479 246.411026}} size 49 angle 1.695017} 48609 {id 48609 c {1397.995160 301.536987} p {{1428.077271 322.549194} {1420.253662 274.268646} {1368.598511 281.003571} {1375.678467 328.876617}} size 48 angle 1.731445} 48611 {id 48611 c {1370.183598 111.469475} p {{1399.739502 131.376297} {1391.639771 85.337204} {1341.105835 91.884697} {1348.329224 138.086731}} size 46 angle 1.744946} 48612 {id 48612 c {1519.304013 386.697516} p {{1550.766846 409.180939} {1541.709717 358.774933} {1489.093506 365.109009} {1495.861572 415.912109}} size 51 angle 1.748583} 48614 {id 48614 c {1486.619487 192.485437} p {{1517.266602 213.760712} {1508.706177 165.099457} {1456.419800 171.520767} {1463.944824 220.600464}} size 49 angle 1.744933} 48617 {id 48617 c {1607.958935 275.600540} p {{1639.266846 297.007874} {1629.765137 248.022018} {1577.122803 254.515793} {1586.114258 303.227722}} size 49 angle 1.762386} 48619 {id 48619 c {1571.899693 85.866461} p {{1602.301147 106.652153} {1592.920166 59.605083} {1542.627441 65.852814} {1550.401001 112.725288}} size 47 angle 1.767611} 48600 {id 48600 c {1206.794202 426.590988} p {{1236.492432 449.318146} {1229.803345 398.072601} {1177.802734 404.404694} {1183.689575 455.227722}} size 51 angle 1.700593} 48602 {id 48602 c {1184.021152 232.821101} p {{1212.459473 253.815598} {1207.137085 204.863739} {1155.541260 211.795914} {1161.424805 260.150055}} size 49 angle 1.679098} 48605 {id 48605 c {1296.399419 316.668400} p {{1325.864990 337.833160} {1318.705078 289.045715} {1267.292847 295.761505} {1274.157593 344.212036}} size 49 angle 1.716513} 48607 {id 48607 c {1272.569361 125.751695} p {{1301.373169 146.699203} {1294.984741 99.184029} {1244.206299 105.124718} {1249.886353 152.636566}} size 47 angle 1.704445} 48608 {id 48608 c {1414.667729 402.124332} p {{1445.368042 424.986145} {1437.862793 373.319275} {1384.357422 379.552948} {1391.050537 431.453613}} size 52 angle 1.715050} 48610 {id 48610 c {1385.344625 207.908486} p {{1415.355225 229.484650} {1408.298096 180.034698} {1355.682983 186.583206} {1362.748413 235.348434}} size 49 angle 1.712552} 48613 {id 48613 c {1504.010825 290.592138} p {{1535.192505 311.400970} {1525.939331 263.201904} {1472.870605 269.810974} {1482.175293 317.866241}} size 49 angle 1.760467} 48615 {id 48615 c {1472.653357 100.909178} p {{1503.442139 121.380783} {1494.246338 74.729080} {1443.124634 81.275391} {1450.703613 127.521828}} size 47 angle 1.765417} 48616 {id 48616 c {1627.703024 377.014268} p {{1659.892212 399.384186} {1649.839233 348.795959} {1595.999512 354.981873} {1604.796143 406.214996}} size 51 angle 1.766962} 48618 {id 48618 c {1590.935498 182.266953} p {{1622.018433 204.144791} {1613.073486 154.467285} {1560.334961 160.728653} {1568.566406 210.356827}} size 50 angle 1.748948}} imageName pose-1781543257841-3.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 99 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-164.252607 -820.689643 321.050974 }{657.240586 2.194841 74.671280 }{-0.091003 -0.007578 0.199975 }} rmse 1.60197092768 tags {48601 {id 48601 c {1141.550955 582.403096} p {{1161.815552 600.761658} {1163.238403 562.024231} {1120.927490 563.719421} {1120.484253 602.198669}} size 38 angle 1.534082} 48603 {id 48603 c {1145.788283 418.406845} p {{1167.404541 439.410339} {1168.944092 395.168213} {1123.939575 397.177490} {1122.794189 441.483185}} size 44 angle 1.536012} 48604 {id 48604 c {1221.678530 654.892956} p {{1241.052490 672.530945} {1243.321289 635.811279} {1201.962158 636.943237} {1200.216064 673.815674}} size 36 angle 1.509088} 48606 {id 48606 c {1229.823309 499.788624} p {{1250.237061 519.468994} {1253.126953 477.784363} {1208.700195 479.424377} {1206.813232 521.515686}} size 41 angle 1.501580} 48609 {id 48609 c {1309.572061 576.229695} p {{1329.272949 595.172302} {1332.628296 555.744568} {1289.946289 557.359314} {1286.864502 596.405029}} size 39 angle 1.485900} 48611 {id 48611 c {1324.503629 410.281911} p {{1345.424316 431.919800} {1348.665894 386.653442} {1303.432983 388.488922} {1300.430908 433.822815}} size 45 angle 1.499307} 48612 {id 48612 c {1386.199225 649.691146} p {{1405.200684 668.071045} {1409.600952 630.438660} {1367.856934 631.948853} {1363.365601 668.476257}} size 37 angle 1.454397} 48614 {id 48614 c {1404.546747 492.311979} p {{1424.596436 512.734863} {1429.509399 470.110352} {1384.809814 472.207672} {1379.893799 514.238159}} size 42 angle 1.456041} 48617 {id 48617 c {1481.319865 570.522647} p {{1500.176636 589.614075} {1506.079590 549.730896} {1462.400513 551.367859} {1457.022339 590.926270}} size 40 angle 1.423857} 48619 {id 48619 c {1505.624037 402.192051} p {{1525.058838 423.735840} {1531.934570 378.371429} {1485.980469 380.416840} {1479.559814 425.789673}} size 45 angle 1.420375} 48600 {id 48600 c {1138.113454 658.341403} p {{1157.728149 676.412109} {1159.237061 639.123474} {1118.033081 639.841675} {1117.274170 677.300659}} size 37 angle 1.530353} 48602 {id 48602 c {1141.823652 502.541629} p {{1163.265625 522.951355} {1164.351807 480.563751} {1119.985718 481.755005} {1119.635254 524.188049}} size 42 angle 1.545177} 48605 {id 48605 c {1223.377045 580.184804} p {{1201.270752 599.937561} {1243.418579 599.076233} {1245.842407 560.111206} {1203.125610 561.095520}} size 42 angle 0.020433} 48607 {id 48607 c {1232.657392 413.568093} p {{1254.376343 435.440247} {1256.473877 390.930359} {1211.246704 392.006378} {1208.927002 436.123993}} size 44 angle 1.523706} 48608 {id 48608 c {1301.878842 653.889951} p {{1320.725586 671.876770} {1324.375000 634.329895} {1282.553223 635.446106} {1278.991821 673.789856}} size 37 angle 1.473904} 48610 {id 48610 c {1314.763363 497.048578} p {{1335.116821 517.577820} {1339.197754 475.334717} {1294.032349 476.138519} {1290.772095 518.368652}} size 42 angle 1.474489} 48613 {id 48613 c {1393.748209 574.806004} p {{1369.902954 595.453003} {1413.156860 593.946838} {1417.280640 554.429871} {1373.905273 555.236877}} size 43 angle 0.034807} 48615 {id 48615 c {1412.617496 407.403562} p {{1433.579224 429.078918} {1438.576172 383.783478} {1391.769043 385.845337} {1387.735352 430.044098}} size 45 angle 1.460922} 48616 {id 48616 c {1468.586555 649.108080} p {{1487.397583 667.221069} {1492.819580 629.765076} {1450.277710 631.478638} {1444.668457 668.199707}} size 37 angle 1.427038} 48618 {id 48618 c {1491.469528 490.510814} p {{1510.942993 511.321289} {1517.885132 468.175201} {1472.139771 469.853912} {1465.745728 512.261475}} size 43 angle 1.411265}} imageName pose-1781543257841-4.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 113 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-652.045996 -21.596042 316.832491 }{38.585632 -605.150208 263.674429 }{-0.025238 0.018629 0.147826 }} rmse 2.01227215325 tags {48601 {id 48601 c {977.930902 159.133678} p {{961.526062 180.890030} {998.662842 173.187088} {994.492188 137.169846} {957.513733 145.293640}} size 37 angle 0.204521} 48603 {id 48603 c {1128.442555 127.285638} p {{1111.380981 149.230835} {1150.937012 141.910492} {1145.978394 104.730423} {1106.935059 113.302460}} size 40 angle 0.182992} 48604 {id 48604 c {913.613811 244.410072} p {{897.504028 265.617676} {933.629150 258.775940} {929.834473 223.056503} {893.546875 230.007172}} size 36 angle 0.187173} 48606 {id 48606 c {1061.222644 215.459666} p {{1044.215210 237.679565} {1082.993774 230.328522} {1078.232056 193.237183} {1039.661499 200.734222}} size 39 angle 0.187342} 48609 {id 48609 c {994.600018 302.540949} p {{978.372559 323.581116} {1015.690918 317.462067} {1011.314331 280.869537} {973.992737 287.961975}} size 37 angle 0.162523} 48611 {id 48611 c {1148.040286 274.979104} p {{1130.848511 296.855865} {1170.356934 290.619507} {1165.280518 253.040680} {1125.903931 259.465057}} size 39 angle 0.156557} 48612 {id 48612 c {929.044403 388.400978} p {{912.621643 409.819275} {949.752258 403.972961} {945.610474 366.795776} {909.082642 373.390045}} size 37 angle 0.156171} 48614 {id 48614 c {1079.629903 363.319986} p {{1062.534424 385.340088} {1101.736694 378.890747} {1096.727173 341.297577} {1058.058228 348.126129}} size 39 angle 0.163054} 48617 {id 48617 c {1011.995130 450.385611} p {{994.765564 472.561249} {1033.851685 466.870331} {1029.125000 428.338287} {990.725464 434.343536}} size 39 angle 0.144583} 48619 {id 48619 c {1168.522487 426.853393} p {{1150.667725 449.554413} {1191.837036 443.555511} {1186.205078 404.371277} {1145.656982 410.472961}} size 41 angle 0.144695} 48600 {id 48600 c {906.411835 177.815006} p {{889.984741 199.787430} {926.487671 191.674118} {922.554993 156.222366} {886.374207 163.982269}} size 37 angle 0.218709} 48602 {id 48602 c {1051.843604 146.397340} p {{1034.971924 168.697723} {1073.739624 160.711548} {1068.651978 124.180634} {1030.366455 132.356964}} size 39 angle 0.203159} 48605 {id 48605 c {986.661165 233.698148} p {{1007.705933 248.093491} {1003.319397 211.708145} {965.541809 219.251785} {970.112244 255.543854}} size 36 angle 1.690775} 48607 {id 48607 c {1137.807079 202.742391} p {{1120.361816 225.086212} {1160.317017 218.317123} {1155.167358 180.507416} {1115.311768 187.177780}} size 40 angle 0.167823} 48608 {id 48608 c {922.560991 318.546825} p {{906.624146 340.189362} {942.870178 333.020996} {938.391785 297.048309} {902.168701 304.013428}} size 36 angle 0.195250} 48610 {id 48610 c {1070.498044 291.328487} p {{1053.658569 313.241547} {1092.294434 306.299133} {1087.534180 269.159515} {1048.903076 276.496185}} size 39 angle 0.177791} 48613 {id 48613 c {1004.548424 378.170736} p {{1026.171143 393.921082} {1021.375305 356.460602} {983.372803 362.746063} {987.668945 399.948730}} size 37 angle 1.698128} 48615 {id 48615 c {1158.497567 351.624066} p {{1141.118408 373.867371} {1181.446045 367.684326} {1175.558594 329.787933} {1136.038452 335.906281}} size 40 angle 0.152136} 48616 {id 48616 c {939.220193 463.734392} p {{922.379578 485.613617} {960.984741 480.247101} {955.976013 441.965332} {918.181152 447.772125}} size 38 angle 0.138125} 48618 {id 48618 c {1090.522811 440.062316} p {{1073.001709 463.023590} {1113.502075 456.692810} {1107.943359 417.232819} {1068.055298 423.802185}} size 40 angle 0.155059}} imageName pose-1781543257841-5.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 127 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-61350.964391 13718.747912 28186.840504 }{4013.252826 -47158.607425 24253.415873 }{0.442939 7.990373 13.206176 }} rmse 2.0423236365 tags {48601 {id 48601 c {995.655720 63.369710} p {{973.477661 90.745377} {1019.583435 88.357903} {1018.224365 35.511921} {971.392822 38.031479}} size 46 angle 0.051736} 48603 {id 48603 c {1180.455537 53.052164} p {{1156.181641 80.391281} {1202.452759 77.794220} {1204.506226 25.964441} {1158.137085 27.948795}} size 46 angle 0.056068} 48604 {id 48604 c {910.089626 169.639338} p {{889.396729 195.435806} {934.235474 192.824677} {931.088196 143.461807} {885.473083 146.002029}} size 44 angle 0.058168} 48606 {id 48606 c {1087.511228 159.278386} p {{1065.120605 184.974594} {1109.740112 182.464233} {1110.227051 133.208969} {1065.099487 135.901810}} size 44 angle 0.056202} 48609 {id 48609 c {1001.921881 257.661450} p {{981.454956 281.020996} {1023.606201 278.443939} {1022.982117 233.624741} {979.547729 236.217819}} size 42 angle 0.061062} 48611 {id 48611 c {1172.079885 247.141943} p {{1150.322266 270.640564} {1191.790283 267.688171} {1194.587402 222.833420} {1151.829712 226.033051}} size 41 angle 0.071077} 48612 {id 48612 c {922.703804 348.671427} p {{903.591309 370.806976} {944.802917 368.033569} {941.781982 326.575623} {900.360535 329.095367}} size 41 angle 0.067195} 48614 {id 48614 c {1086.742713 338.234140} p {{1066.020996 360.519623} {1107.078979 357.741791} {1107.172485 316.262634} {1066.420776 318.740234}} size 41 angle 0.067553} 48617 {id 48617 c {1007.363271 423.517549} p {{987.993103 444.138885} {1027.957153 441.846527} {1026.905151 402.713409} {987.214966 405.585144}} size 40 angle 0.057298} 48619 {id 48619 c {1165.054318 412.989596} p {{1144.602783 433.873840} {1183.831665 430.969727} {1185.664429 391.943420} {1146.122681 394.861725}} size 39 angle 0.073895} 48600 {id 48600 c {901.093923 70.459400} p {{879.565063 98.831100} {926.215210 95.174049} {922.728394 41.948521} {875.173706 44.958752}} size 46 angle 0.078233} 48602 {id 48602 c {1085.779535 59.660986} p {{1062.445923 87.665062} {1108.789673 85.055267} {1109.044922 31.738792} {1062.930176 34.444141}} size 46 angle 0.056254} 48605 {id 48605 c {997.285938 166.825402} p {{973.270996 143.105530} {975.749329 192.658005} {1021.540161 190.781616} {1018.919434 140.876587}} size 49 angle -1.520824} 48607 {id 48607 c {1173.617485 154.937350} p {{1150.805542 180.724335} {1195.427490 177.985092} {1197.802246 127.598511} {1151.804687 131.886658}} size 44 angle 0.061311} 48608 {id 48608 c {915.100492 265.275558} p {{895.314270 289.225830} {938.357666 286.459778} {935.249207 240.886505} {891.717712 243.976929}} size 43 angle 0.064174} 48610 {id 48610 c {1085.493242 255.170662} p {{1064.236572 278.830505} {1106.522827 275.830505} {1107.605225 230.558807} {1063.488892 233.553192}} size 42 angle 0.070826} 48613 {id 48613 c {1003.760979 346.516282} p {{982.015869 326.394714} {984.393250 368.502594} {1025.032593 366.199707} {1023.765808 323.806732}} size 42 angle -1.514397} 48615 {id 48615 c {1167.279457 334.932959} p {{1146.137329 356.945221} {1186.635132 354.646179} {1188.529785 312.808044} {1147.281250 314.565338}} size 40 angle 0.056709} 48616 {id 48616 c {927.208690 432.071257} p {{908.725525 452.526123} {949.156921 450.607025} {946.694458 410.506836} {905.706055 413.911804}} size 40 angle 0.047430} 48618 {id 48618 c {1085.678921 420.576598} p {{1065.630981 441.996979} {1105.944946 439.000702} {1105.520752 399.376434} {1065.620117 402.340881}} size 40 angle 0.074187}} imageName pose-1781543257841-6.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 139 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1293234.230097 -236546.444378 661933.879650 }{123504.689570 -1164505.518365 389497.399567 }{-24.466768 -74.390643 296.571025 }} rmse 1.41663092406 tags {48601 {id 48601 c {949.478206 319.501544} p {{930.948975 336.128265} {970.724487 329.256683} {967.531921 303.301514} {928.905212 310.055542}} size 40 angle 0.171071} 48603 {id 48603 c {1108.382342 293.125748} p {{1091.457397 309.351135} {1132.334351 302.969696} {1125.304199 276.903320} {1085.332153 283.652435}} size 41 angle 0.154863} 48604 {id 48604 c {873.740912 387.403626} p {{853.658752 405.510284} {894.607117 398.498199} {893.467712 369.617371} {852.656311 376.192932}} size 41 angle 0.169597} 48606 {id 48606 c {1038.223024 362.779168} p {{1020.033813 380.388397} {1062.753662 374.629364} {1056.753296 344.839752} {1015.530884 351.817108}} size 43 angle 0.134001} 48609 {id 48609 c {962.427428 434.368246} p {{941.884705 454.018036} {986.398438 446.855377} {982.145691 415.507080} {938.896179 422.110199}} size 45 angle 0.159541} 48611 {id 48611 c {1138.240590 411.331288} p {{1119.195923 430.997711} {1164.848633 424.473511} {1155.939697 393.054352} {1111.961914 398.351746}} size 46 angle 0.141948} 48612 {id 48612 c {878.276910 515.929814} p {{855.905457 537.082336} {902.737427 530.844604} {900.828247 494.607208} {855.529419 502.059540}} size 47 angle 0.132415} 48614 {id 48614 c {1062.340061 487.695207} p {{1041.345215 509.091980} {1089.702148 502.621124} {1082.033081 467.625183} {1035.657471 473.139954}} size 48 angle 0.133024} 48617 {id 48617 c {977.755158 575.323222} p {{955.283936 598.861938} {1005.151978 591.779480} {999.932617 552.092224} {951.709961 559.678833}} size 50 angle 0.141080} 48619 {id 48619 c {1175.241702 547.766057} p {{1155.157227 570.688110} {1206.051147 564.145264} {1194.967285 525.253601} {1145.051514 531.716064}} size 51 angle 0.127857} 48600 {id 48600 c {869.726321 330.031056} p {{850.153198 347.147217} {890.231140 340.157562} {888.217468 313.861053} {849.431213 320.008118}} size 40 angle 0.172665} 48602 {id 48602 c {1027.292091 304.874545} p {{1009.680237 321.058594} {1050.356445 314.883850} {1045.061035 288.546143} {1005.118835 295.251953}} size 41 angle 0.150652} 48605 {id 48605 c {954.464210 373.169764} p {{932.091919 362.031342} {934.827820 391.160309} {977.714783 384.745453} {973.484131 355.744019}} size 29 angle -1.477147} 48607 {id 48607 c {1121.511416 347.373795} p {{1103.990112 365.026520} {1147.302490 359.805634} {1139.057983 329.695618} {1097.288696 335.697937}} size 43 angle 0.119962} 48608 {id 48608 c {874.893165 446.438284} p {{853.459473 466.811462} {898.051331 459.668365} {895.612122 426.744476} {852.912964 433.881165}} size 45 angle 0.158839} 48610 {id 48610 c {1049.016566 421.271853} p {{1029.286255 440.778168} {1074.801270 434.455658} {1068.158569 402.347168} {1023.870789 408.414734}} size 45 angle 0.138027} 48613 {id 48613 c {968.935134 500.034932} p {{943.878113 485.345337} {947.116699 521.777832} {995.350952 515.521118} {990.469421 478.575195}} size 36 angle -1.482137} 48615 {id 48615 c {1154.787958 474.180003} p {{1135.341919 495.410980} {1184.017578 489.054199} {1173.784912 453.439331} {1126.531982 459.801270}} size 49 angle 0.129860} 48616 {id 48616 c {880.531426 588.127394} p {{856.710999 611.316040} {906.284851 605.006714} {904.167236 565.118469} {855.683960 571.841858}} size 49 angle 0.126591} 48618 {id 48618 c {1075.733811 560.537017} p {{1054.046997 584.490234} {1104.965942 577.225769} {1096.608521 537.480774} {1047.277100 544.290955}} size 51 angle 0.141711}} imageName pose-1781543257841-7.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 158 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-3671321.265916 -136949.507711 2544618.126158 }{710108.103504 -4109714.560197 1388714.600088 }{203.442819 176.896104 872.758912 }} rmse 1.7736504896 tags {48601 {id 48601 c {642.392194 133.357953} p {{617.967773 158.737991} {672.279236 157.610672} {666.108459 108.713776} {612.277710 108.920670}} size 54 angle 0.020754} 48603 {id 48603 c {844.852518 132.784390} p {{822.703674 157.752472} {871.943237 155.121231} {865.329102 109.701424} {816.836548 109.684662}} size 49 angle 0.053387} 48604 {id 48604 c {544.373174 234.091164} p {{518.562195 260.513550} {575.344910 258.714539} {570.413330 207.434174} {512.823120 209.008011}} size 56 angle 0.031672} 48606 {id 48606 c {758.088901 229.356579} p {{735.210571 254.415009} {786.411987 252.761688} {780.482178 204.829422} {728.771057 205.129440}} size 51 angle 0.032279} 48609 {id 48609 c {665.531838 330.499630} p {{641.712585 356.745972} {695.350830 354.274567} {689.092102 304.538666} {635.630066 306.658691}} size 53 angle 0.046043} 48611 {id 48611 c {868.893259 319.759095} p {{847.957031 344.389862} {895.765808 342.600800} {889.633667 295.358704} {841.706055 296.649933}} size 47 angle 0.037404} 48612 {id 48612 c {567.420051 439.360050} p {{541.064819 468.426208} {599.423706 463.539520} {593.042664 411.101868} {535.535828 415.270813}} size 58 angle 0.083540} 48614 {id 48614 c {782.684121 422.996243} p {{759.732910 450.327362} {812.032654 445.964630} {805.213684 396.167236} {753.646423 400.271118}} size 52 angle 0.083225} 48617 {id 48617 c {690.240621 532.690635} p {{665.525635 561.614380} {720.572815 555.544250} {714.737122 504.022583} {659.297363 509.376617}} size 55 angle 0.109828} 48619 {id 48619 c {894.948644 511.727718} p {{873.199768 539.352783} {923.236877 534.105225} {916.227539 484.699615} {866.586121 489.291443}} size 50 angle 0.104491} 48600 {id 48600 c {534.750759 135.390685} p {{508.569702 161.553513} {566.256531 161.074783} {560.640137 109.519333} {502.975861 109.487190}} size 57 angle 0.008299} 48602 {id 48602 c {746.947710 134.937998} p {{723.971497 159.439575} {776.209045 159.769836} {769.576782 110.806610} {717.985352 110.359879}} size 52 angle -0.006322} 48605 {id 48605 c {655.668106 233.310392} p {{680.179504 207.696640} {624.799927 208.207703} {631.000854 259.087006} {685.842834 257.849152}} size 55 angle -3.132365} 48607 {id 48607 c {856.791753 227.330298} p {{835.554993 251.461700} {884.879150 251.208878} {878.426758 202.746368} {829.209656 203.881302}} size 49 angle 0.005126} 48608 {id 48608 c {556.857705 337.416902} p {{531.402344 365.235870} {588.602234 361.786133} {581.787415 310.172394} {524.963501 312.932770}} size 57 angle 0.060237} 48610 {id 48610 c {771.564042 327.611774} p {{749.380554 353.552917} {799.942505 350.367218} {793.670471 301.760742} {742.782227 304.532898}} size 50 angle 0.062923} 48613 {id 48613 c {680.121954 433.080485} p {{704.556458 405.732422} {649.144653 409.019745} {654.927063 461.279602} {711.183899 457.206970}} size 55 angle -3.082337} 48615 {id 48615 c {882.796758 417.159998} p {{860.786133 443.784180} {911.162842 440.625854} {903.889832 391.645691} {854.756836 393.963959}} size 50 angle 0.062612} 48616 {id 48616 c {580.346089 546.081070} p {{553.940918 575.834351} {612.320435 569.507202} {606.885620 516.176392} {547.775391 522.218018}} size 58 angle 0.107958} 48618 {id 48618 c {796.660210 523.128245} p {{773.319641 551.862793} {825.849243 545.705505} {819.719788 494.739624} {766.974731 500.166992}} size 52 angle 0.116683}} imageName pose-1781543257841-8.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 237 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1891.405861 1041.655384 2016.225692 }{520.247195 -2581.867798 882.220288 }{0.314318 0.305814 0.589245 }} rmse 3.33980752481 tags {48601 {id 48601 c {364.371225 154.206433} p {{331.795715 179.574631} {398.034821 189.569305} {395.756592 129.765060} {330.482635 118.607208}} size 66 angle -0.149758} 48603 {id 48603 c {596.617941 193.608417} p {{569.365417 215.626068} {621.879395 224.079178} {623.512268 171.880157} {570.107422 161.631012}} size 53 angle -0.159600} 48604 {id 48604 c {233.031368 256.033977} p {{198.913910 282.412262} {268.121460 288.495392} {267.337982 229.509445} {195.164581 221.003876}} size 69 angle -0.087672} 48606 {id 48606 c {486.550832 282.978654} p {{457.602051 306.474640} {514.791077 312.368927} {514.793640 260.055664} {457.518707 252.764252}} size 57 angle -0.102704} 48609 {id 48609 c {369.163334 379.775009} p {{338.807770 404.953491} {400.322906 407.798096} {398.998322 355.028320} {336.650604 350.534973}} size 61 angle -0.046209} 48611 {id 48611 c {592.702856 393.589059} p {{566.986328 416.086365} {617.135071 418.671417} {617.891846 371.553253} {567.347168 367.558655}} size 50 angle -0.051502} 48612 {id 48612 c {245.957694 484.046393} p {{212.855713 511.161255} {280.776245 510.973358} {278.629791 457.283661} {209.693771 456.001648}} size 67 angle 0.002766} 48614 {id 48614 c {487.158600 485.320641} p {{459.366730 509.293365} {514.243896 509.179474} {514.503540 461.733429} {459.173187 460.668915}} size 54 angle 0.002075} 48617 {id 48617 c {375.237326 583.398845} p {{345.979401 609.102905} {405.023529 605.900635} {403.759338 558.341309} {344.480438 560.163757}} size 59 angle 0.054182} 48619 {id 48619 c {587.942277 574.730119} p {{563.161377 597.582275} {610.900452 594.895813} {611.961670 552.580200} {564.200806 553.876404}} size 47 angle 0.056215} 48600 {id 48600 c {226.374950 127.267377} p {{189.934280 153.998489} {264.650635 164.867844} {262.333344 100.890038} {186.153687 87.755653}} size 75 angle -0.144462} 48602 {id 48602 c {486.868933 171.379722} p {{455.991943 194.898392} {516.005554 204.446930} {517.362671 148.152969} {456.641235 137.074249}} size 60 angle -0.157784} 48605 {id 48605 c {365.335940 265.382087} p {{397.465179 297.087921} {397.123322 241.078461} {331.988190 232.473801} {333.097260 290.030762}} size 56 angle 1.576900} 48607 {id 48607 c {593.918332 292.977820} p {{567.305542 315.167755} {617.385620 319.511688} {620.053650 271.186005} {568.262878 263.969849}} size 50 angle -0.086523} 48608 {id 48608 c {236.291299 366.820416} p {{202.024750 393.381042} {272.369934 397.377472} {269.129639 341.366821} {198.805801 335.071808}} size 70 angle -0.056751} 48610 {id 48610 c {486.311857 383.896561} p {{457.866730 407.818268} {514.040649 410.630219} {514.123901 360.507263} {457.134186 355.766022}} size 56 angle -0.050016} 48613 {id 48613 c {370.907103 480.363625} p {{402.015625 506.210236} {401.381683 455.518799} {338.221100 453.206360} {339.819580 505.708160}} size 50 angle 1.583302} 48615 {id 48615 c {588.610704 483.153853} p {{563.043274 506.112549} {612.937317 506.486633} {613.698975 460.625427} {563.892517 459.445496}} size 49 angle -0.007497} 48616 {id 48616 c {247.747799 583.097366} p {{215.949295 610.146484} {282.119080 607.427429} {278.761658 556.715698} {212.549408 558.181824}} size 66 angle 0.041069} 48618 {id 48618 c {485.557389 575.696389} p {{458.575623 599.804138} {511.779755 597.280396} {512.143311 551.942322} {458.491974 553.418457}} size 53 angle 0.047400}} imageName pose-1781543257841-9.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 271 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-263.442465 -3993.519151 3622.146186 }{3838.120310 362.146076 1127.873075 }{-0.281576 0.033683 0.956437 }} rmse 2.30152949436 tags {48601 {id 48601 c {198.621573 241.319812} p {{222.522720 260.372314} {216.912018 217.634796} {174.017868 221.707275} {181.274582 263.783112}} size 43 angle 1.701333} 48603 {id 48603 c {170.962676 67.695843} p {{197.280319 89.311028} {187.799377 43.787811} {145.962463 47.162689} {153.747971 92.140640}} size 46 angle 1.776127} 48604 {id 48604 c {293.592474 318.039051} p {{317.013885 337.112396} {311.371521 295.126556} {269.805115 298.667694} {276.050354 340.646210}} size 42 angle 1.704383} 48606 {id 48606 c {270.454320 148.843220} p {{295.507935 169.239349} {289.732910 124.954781} {245.201157 128.284637} {251.416473 172.433350}} size 44 angle 1.700472} 48609 {id 48609 c {365.796203 226.761980} p {{389.959595 246.366608} {384.328979 203.366684} {341.377594 206.950287} {347.695770 249.611496}} size 43 angle 1.701000} 48611 {id 48611 c {342.683495 55.350728} p {{366.480438 74.572601} {360.948029 32.722778} {317.286224 34.836197} {324.416443 77.981796}} size 42 angle 1.702231} 48612 {id 48612 c {460.969073 304.179221} p {{484.815125 323.147705} {479.274994 281.422089} {436.590271 284.786957} {443.134369 326.350555}} size 42 angle 1.702800} 48614 {id 48614 c {438.893249 134.686283} p {{463.889557 155.440750} {457.597778 110.989212} {414.331299 114.292465} {420.062805 158.542877}} size 44 angle 1.711405} 48617 {id 48617 c {533.080383 213.173669} p {{557.535583 233.393188} {551.556335 189.925522} {509.016449 193.277649} {514.665344 236.345169}} size 43 angle 1.707495} 48619 {id 48619 c {511.162161 40.181078} p {{535.220459 60.709080} {529.012695 17.277449} {487.738098 20.194244} {492.589447 64.011322}} size 43 angle 1.712767} 48602 {id 48602 c {183.638056 152.018918} p {{209.137878 172.819244} {202.462860 127.247940} {158.109695 131.195312} {165.382980 176.040207}} size 46 angle 1.716236} 48605 {id 48605 c {280.437145 231.136902} p {{261.948456 254.223755} {304.560974 250.985748} {299.074646 207.864227} {256.200226 211.195007}} size 42 angle 0.075841} 48607 {id 48607 c {255.648743 58.022969} p {{280.276367 78.527657} {273.481659 34.840279} {230.918121 37.432526} {237.351044 81.809875}} size 44 angle 1.725090} 48608 {id 48608 c {374.839880 308.191019} p {{398.570862 327.621948} {393.538696 285.166840} {350.828522 288.530518} {356.646088 330.593353}} size 42 angle 1.688775} 48610 {id 48610 c {353.426549 139.437219} p {{378.838562 160.236038} {372.627075 115.518738} {328.744843 119.236130} {334.531097 162.975662}} size 45 angle 1.708819} 48613 {id 48613 c {447.986478 217.436763} p {{429.169769 240.373611} {472.259338 237.322754} {467.006531 194.252045} {423.699921 197.539551}} size 43 angle 0.070685} 48615 {id 48615 c {425.381881 44.997536} p {{449.748932 65.453217} {443.391968 21.960690} {402.644073 25.909575} {406.869446 68.676941}} size 43 angle 1.715931} 48616 {id 48616 c {542.267473 295.145410} p {{565.842590 314.410583} {560.579468 272.551575} {518.264099 275.530273} {524.113098 317.544769}} size 42 angle 1.695874} 48618 {id 48618 c {520.425825 125.529852} p {{545.750671 146.685135} {538.838501 101.829994} {496.323822 105.396080} {501.663605 149.679626}} size 45 angle 1.723693}} imageName pose-1781543257841-10.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 286 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{50.824095 -712.814483 1047.080530 }{1220.638908 279.244176 172.091587 }{-0.050051 0.134620 0.274120 }} rmse 1.70201751052 tags {48601 {id 48601 c {72.271242 414.743317} p {{109.223740 440.646667} {102.671288 390.229553} {35.977558 389.301788} {40.616467 440.268860}} size 50 angle 1.700037} 48603 {id 48603 c {54.034779 217.560069} p {{89.145515 245.273972} {86.687927 196.433075} {16.739708 188.122009} {21.451021 238.642166}} size 48 angle 1.621072} 48604 {id 48604 c {205.449907 509.739067} p {{237.443558 532.384338} {232.669586 485.308655} {172.757889 486.599487} {177.778259 534.575134}} size 47 angle 1.671861} 48606 {id 48606 c {186.127986 322.854836} p {{216.630951 347.064301} {212.562012 302.016602} {154.300674 297.594269} {158.851440 344.357239}} size 45 angle 1.660877} 48609 {id 48609 c {307.253575 416.963510} p {{337.794800 439.960144} {330.584656 395.770905} {277.674011 394.690979} {282.244781 439.680054}} size 44 angle 1.732536} 48611 {id 48611 c {287.998633 243.027042} p {{315.487518 266.903290} {311.848602 224.639084} {259.013916 217.851547} {263.363373 262.020447}} size 42 angle 1.656684} 48612 {id 48612 c {417.887151 502.336126} p {{444.486633 522.683228} {439.543701 480.797607} {390.688629 481.530792} {395.722961 524.379517}} size 42 angle 1.688263} 48614 {id 48614 c {397.370296 335.164383} p {{424.254028 357.527649} {418.144684 316.253967} {370.656311 312.942322} {375.638885 354.945953}} size 41 angle 1.717750} 48617 {id 48617 c {499.446103 419.795104} p {{524.130798 440.142609} {518.483093 400.440186} {474.786102 399.467957} {479.741669 439.828613}} size 40 angle 1.712099} 48619 {id 48619 c {479.151452 262.342380} p {{503.282379 284.006531} {498.348785 245.130402} {454.578003 240.280945} {459.620728 279.853271}} size 39 angle 1.697027} 48600 {id 48600 c {77.699261 512.609928} p {{113.413376 536.890869} {108.199699 486.683990} {41.208942 487.801270} {46.064499 539.500061}} size 50 angle 1.674269} 48605 {id 48605 c {193.944591 415.181222} p {{161.437576 390.916840} {165.369568 439.293060} {226.656128 439.598267} {220.324692 392.921478}} size 48 angle -1.489695} 48607 {id 48607 c {176.552192 230.694903} p {{207.905884 256.611755} {204.110565 210.874542} {143.436234 203.321365} {148.534119 250.845886}} size 45 angle 1.653588} 48608 {id 48608 c {313.934619 506.088315} p {{344.029724 528.150574} {338.209686 483.178070} {283.309875 483.637787} {288.532684 530.062073}} size 45 angle 1.699494} 48610 {id 48610 c {296.282791 329.818533} p {{325.236298 353.672607} {320.333221 310.113373} {267.727356 306.292419} {271.577606 350.060150}} size 43 angle 1.682886} 48613 {id 48613 c {406.646786 419.554464} p {{379.693573 397.918732} {383.775238 440.470154} {433.692444 441.264404} {428.465881 399.601227}} size 42 angle -1.475166} 48615 {id 48615 c {388.513550 253.961729} p {{414.263428 276.515167} {410.385437 236.083435} {362.790558 231.431839} {366.332153 272.093018}} size 40 angle 1.666418} 48616 {id 48616 c {507.837697 501.472006} p {{532.209351 521.014099} {527.509155 481.012390} {482.639832 481.267426} {487.555908 522.566406}} size 40 angle 1.687760} 48618 {id 48618 c {488.165975 341.681269} p {{513.142700 363.443085} {506.917389 323.423706} {463.470276 320.164307} {468.794586 360.542480}} size 40 angle 1.725117}} imageName pose-1781543257841-11.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 310 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{766892.576057 -19515.503279 451640.762142 }{23960.984967 703560.433782 93720.310217 }{49.603996 -23.693156 159.828412 }} rmse 1.83027038725 tags {48601 {id 48601 c {432.038537 553.445692} p {{449.389191 528.153564} {414.490356 532.363770} {415.014954 578.261047} {449.635620 574.586365}} size 35 angle -3.021533} 48603 {id 48603 c {302.262651 569.126614} p {{318.298492 545.140564} {285.711456 548.772949} {287.065430 591.858276} {318.288391 588.834106}} size 32 angle -3.030584} 48604 {id 48604 c {500.794313 450.427968} p {{519.482239 422.830261} {481.857849 429.776672} {483.057526 476.621063} {519.694641 471.039856}} size 38 angle -2.959023} 48606 {id 48606 c {365.341744 472.858152} p {{381.949127 447.837952} {349.402557 453.597107} {349.204224 497.170471} {381.573456 492.472687}} size 33 angle -2.966454} 48609 {id 48609 c {429.053209 371.806219} p {{445.609863 345.667053} {411.475128 352.892456} {412.795074 397.474091} {446.470551 390.547028}} size 34 angle -2.932999} 48611 {id 48611 c {302.674349 398.168756} p {{316.837280 373.322449} {289.007324 380.852509} {288.867432 422.390503} {316.956909 416.264893}} size 28 angle -2.877346} 48612 {id 48612 c {496.276042 264.759201} p {{513.637085 237.214569} {477.861755 246.603622} {479.160706 291.914001} {514.729065 282.952972}} size 36 angle -2.884936} 48614 {id 48614 c {363.212078 299.003323} p {{379.272125 273.819183} {347.609619 282.036316} {347.335876 323.899170} {379.685486 316.917450}} size 32 angle -2.887672} 48617 {id 48617 c {427.922356 195.767095} p {{445.219391 168.574158} {411.057007 178.722443} {411.071198 222.259064} {444.654907 212.677536}} size 35 angle -2.852835} 48619 {id 48619 c {304.872502 233.641435} p {{319.946808 208.123108} {291.097809 217.632965} {290.434784 258.082123} {318.112488 249.028488}} size 30 angle -2.823167} 48600 {id 48600 c {501.221953 543.284653} p {{520.159790 516.529175} {482.061554 521.702759} {482.690491 569.466003} {521.101440 565.676514}} size 38 angle -3.006622} 48602 {id 48602 c {362.055178 560.390636} p {{378.363037 535.925354} {345.495270 539.720520} {345.660431 584.986267} {378.310333 580.680359}} size 33 angle -3.026634} 48605 {id 48605 c {428.911134 460.333650} p {{411.418060 485.897827} {447.390472 480.925568} {447.014984 433.876892} {411.214752 440.614197}} size 36 angle 0.137354} 48607 {id 48607 c {299.170137 480.372077} p {{315.152313 456.267578} {284.449646 461.873840} {283.119354 504.580048} {315.378815 500.740417}} size 31 angle -2.960984} 48608 {id 48608 c {497.456230 354.845126} p {{515.249817 326.969238} {479.143768 336.376831} {479.984161 382.217316} {516.885071 374.439301}} size 37 angle -2.886705} 48610 {id 48610 c {362.066778 384.370008} p {{378.052521 358.907959} {345.932373 365.576324} {346.316467 409.457062} {378.003723 402.933685}} size 32 angle -2.936894} 48613 {id 48613 c {426.550325 281.249530} p {{409.839600 307.328125} {444.106659 299.489532} {443.746246 254.413742} {409.587128 263.625763}} size 35 angle 0.224881} 48616 {id 48616 c {495.222277 174.174471} p {{513.788574 145.978683} {477.288757 157.132172} {477.218567 201.515884} {513.863220 191.889038}} size 38 angle -2.845028} 48618 {id 48618 c {362.450130 213.833265} p {{379.252136 187.789291} {346.920319 197.150696} {346.528229 238.513031} {378.182556 230.733490}} size 33 angle -2.859758}} imageName pose-1781543257841-12.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 336 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{4603.471570 134559.198783 47159.825235 }{-135326.500196 5334.233566 57404.380517 }{-0.661932 0.140649 30.635474 }} rmse 1.34260804628 tags {48601 {id 48601 c {1073.750515 175.041853} p {{1052.528687 157.187790} {1052.229614 193.388962} {1095.322754 193.190720} {1094.947021 156.971298}} size 36 angle -1.579058} 48603 {id 48603 c {1074.066976 324.507615} p {{1052.206787 305.428101} {1052.459229 343.463501} {1096.251709 343.870392} {1096.289062 305.012787}} size 38 angle -1.564159} 48604 {id 48604 c {991.370515 107.495040} p {{971.912415 90.922264} {970.732605 125.059685} {1012.167603 125.208252} {1012.146545 89.812843}} size 34 angle -1.605343} 48606 {id 48606 c {988.277975 249.339919} p {{967.488159 230.941681} {966.608826 267.273804} {1009.637512 268.242340} {1010.369141 231.056763}} size 36 angle -1.594994} 48609 {id 48609 c {907.009210 175.727970} p {{887.060913 157.463745} {885.001831 193.691315} {927.278198 194.285812} {928.883423 157.873322}} size 36 angle -1.627573} 48611 {id 48611 c {899.603721 323.934888} p {{878.815857 303.766144} {877.170288 343.879761} {920.487305 344.196503} {922.151794 303.888092}} size 40 angle -1.611796} 48612 {id 48612 c {829.132043 104.562774} p {{810.125427 86.692841} {807.380005 121.667053} {848.812683 123.066422} {850.246216 87.960068}} size 35 angle -1.649134} 48614 {id 48614 c {818.998538 247.498701} p {{798.753723 228.354401} {796.158691 265.858429} {838.737915 266.165039} {841.599487 229.331009}} size 37 angle -1.639880} 48617 {id 48617 c {741.013150 172.140930} p {{721.825806 153.315475} {717.891663 189.537949} {760.464600 191.225510} {763.652710 155.106522}} size 36 angle -1.678983} 48619 {id 48619 c {725.870029 321.457629} p {{706.293152 301.516876} {702.403625 340.028595} {745.532410 341.485474} {749.751099 302.558502}} size 38 angle -1.671451} 48600 {id 48600 c {1074.052102 105.429277} p {{1053.495850 88.308304} {1053.453979 123.142807} {1095.533203 123.320541} {1094.498901 87.845879}} size 34 angle -1.571998} 48602 {id 48602 c {1075.037272 247.719933} p {{1052.954712 228.852646} {1053.197266 266.806152} {1097.088257 266.560242} {1096.558472 228.912323}} size 37 angle -1.564406} 48605 {id 48605 c {991.462856 176.293567} p {{970.636841 157.802673} {969.213196 195.071320} {1012.382080 194.867218} {1013.173828 157.970444}} size 37 angle -1.608977} 48607 {id 48607 c {988.271297 323.409970} p {{966.160828 303.230164} {965.943604 343.330688} {1010.088562 343.322174} {1010.208191 303.837921}} size 40 angle -1.576213} 48608 {id 48608 c {911.985226 106.559502} p {{891.915039 88.722786} {890.529480 123.506119} {931.588745 123.981483} {933.158203 89.836227}} size 34 angle -1.610609} 48610 {id 48610 c {904.876075 247.834935} p {{884.256775 228.930695} {882.191711 266.480865} {925.678406 266.906982} {927.533142 229.211441}} size 37 angle -1.625736} 48613 {id 48613 c {825.474011 173.685320} p {{805.874146 155.010681} {802.850891 191.792252} {845.849548 193.099014} {848.043945 155.620956}} size 36 angle -1.652807} 48615 {id 48615 c {814.123097 321.664336} p {{793.880493 301.762512} {790.620117 341.099457} {835.070190 342.258789} {837.308655 302.491699}} size 39 angle -1.653491} 48616 {id 48616 c {749.620519 102.389401} p {{730.910706 84.664383} {727.124084 119.449913} {768.818787 120.577164} {771.829041 85.547234}} size 34 angle -1.679226} 48618 {id 48618 c {735.360506 244.450282} p {{715.602051 225.177017} {711.425720 262.848114} {755.005920 263.613281} {758.853516 226.392029}} size 37 angle -1.681208}} imageName pose-1781543257841-13.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 349 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-42006.056341 618407.989571 46334.318232 }{-565093.723952 -27983.125273 251552.732742 }{26.922105 54.178774 129.547352 }} rmse 0.738898030151 tags {48601 {id 48601 c {1583.305303 145.282432} p {{1553.724854 133.092209} {1563.607910 174.091873} {1613.596924 157.765732} {1603.335205 115.986664}} size 42 angle -1.334257} 48603 {id 48603 c {1623.495857 309.412621} p {{1593.311890 295.631622} {1603.908203 336.235626} {1654.117798 323.393585} {1643.897461 281.475006}} size 41 angle -1.315523} 48604 {id 48604 c {1471.273914 100.575907} p {{1445.189575 90.033272} {1453.117554 128.696182} {1499.084229 111.816139} {1489.562866 72.250275}} size 39 angle -1.368546} 48606 {id 48606 c {1507.686781 256.319445} p {{1479.963989 243.632904} {1489.166260 282.961151} {1535.705322 269.141327} {1526.807739 228.814011}} size 40 angle -1.340945} 48609 {id 48609 c {1401.802316 207.969095} p {{1376.445190 196.288300} {1384.526978 234.246750} {1427.940308 220.009598} {1419.446411 181.130524}} size 38 angle -1.361017} 48611 {id 48611 c {1435.122709 360.461753} p {{1409.137939 346.993469} {1417.652100 385.808502} {1461.908081 374.345001} {1452.723511 334.926117}} size 39 angle -1.354864} 48612 {id 48612 c {1304.792060 163.544640} p {{1281.339722 152.543762} {1288.938965 189.175308} {1328.660156 174.740540} {1320.708984 137.810776}} size 37 angle -1.366247} 48614 {id 48614 c {1335.437698 309.322675} p {{1311.624146 297.276917} {1319.497681 333.455688} {1359.369629 321.428314} {1351.731812 284.653564}} size 37 angle -1.356509} 48617 {id 48617 c {1243.749759 262.137148} p {{1221.931274 250.747498} {1228.881592 285.992737} {1265.767822 273.630981} {1258.832153 237.937836}} size 35 angle -1.376096} 48619 {id 48619 c {1272.913442 404.925019} p {{1250.692993 392.101196} {1257.740112 428.166321} {1295.694092 418.072144} {1288.293701 381.366760}} size 36 angle -1.377828} 48600 {id 48600 c {1564.066360 65.587149} p {{1535.401978 54.913307} {1544.859375 94.562202} {1593.631592 76.596443} {1583.183472 36.747677}} size 40 angle -1.336643} 48602 {id 48602 c {1603.038917 226.582457} p {{1572.679565 213.412918} {1582.847534 254.925323} {1633.826782 239.937881} {1623.557983 197.779617}} size 42 angle -1.330587} 48605 {id 48605 c {1488.559622 178.892756} p {{1469.938721 206.515533} {1516.978638 191.118256} {1507.937988 150.146332} {1460.885254 166.987595}} size 49 angle 0.316332} 48607 {id 48607 c {1526.241290 334.702058} p {{1498.980103 321.365814} {1506.401367 362.501465} {1555.100708 348.820160} {1545.040161 308.361359}} size 41 angle -1.392307} 48608 {id 48608 c {1384.624545 133.919279} p {{1359.451660 122.670517} {1367.424805 161.219101} {1410.523193 145.492355} {1401.587036 106.996025}} size 39 angle -1.366839} 48610 {id 48610 c {1417.455410 284.507754} p {{1391.823120 272.121887} {1400.070435 310.095215} {1443.510010 297.097687} {1435.313721 258.223633}} size 38 angle -1.356931} 48613 {id 48613 c {1319.617852 236.336932} p {{1303.319336 261.778351} {1343.896973 248.560242} {1336.254272 210.368057} {1295.936890 224.414764}} size 42 angle 0.314909} 48615 {id 48615 c {1350.581998 384.136254} p {{1326.474976 370.715607} {1334.264893 408.357025} {1375.247803 397.867981} {1367.291260 359.333374}} size 38 angle -1.366726} 48616 {id 48616 c {1229.578846 191.805533} p {{1207.622070 180.703964} {1214.551758 216.823944} {1252.010010 203.146957} {1244.745361 166.554993}} size 36 angle -1.381248} 48618 {id 48618 c {1258.106145 333.438437} p {{1236.033203 321.214142} {1243.164917 356.981049} {1280.836792 346.026978} {1273.311035 309.480377}} size 36 angle -1.373983}} imageName pose-1781543257841-14.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg}}} {point {862.566467 507.444885} det {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221} width 1920 points {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} id 48618 posesReport {
<p>Poses:</p><ol>
<li style="padding-bottom: 1em">
RMSE 0.725728225238
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-0.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1367.43,391.922 1405.21,389.763 1402.77,354.724 1364.97,357.133 1367.43,391.922" fill="none" stroke="green" stroke-width="3" />
<text x="1367.431885" y="391.921936" fill="green" font-size="12">48601</text>
<polyline points="1520.25,382.996 1560.27,380.483 1556.39,345.479 1516.82,348.073 1520.25,382.996" fill="none" stroke="green" stroke-width="3" />
<text x="1520.251709" y="382.996368" fill="green" font-size="12">48603</text>
<polyline points="1296.98,465.833 1334.82,464.71 1332.75,428.698 1294.88,430.397 1296.98,465.833" fill="none" stroke="green" stroke-width="3" />
<text x="1296.983887" y="465.832520" fill="green" font-size="12">48604</text>
<polyline points="1448.43,459.266 1487.84,457.079 1484.45,420.929 1445.62,422.948 1448.43,459.266" fill="none" stroke="green" stroke-width="3" />
<text x="1448.426758" y="459.265656" fill="green" font-size="12">48606</text>
<polyline points="1377.01,533.713 1415.9,532.741 1413.31,495.927 1374.51,497.628 1377.01,533.713" fill="none" stroke="green" stroke-width="3" />
<text x="1377.006226" y="533.712585" fill="green" font-size="12">48609</text>
<polyline points="1533.44,527.498 1572.45,526.568 1569.05,489.148 1530.55,490.243 1533.44,527.498" fill="none" stroke="green" stroke-width="3" />
<text x="1533.442505" y="527.498169" fill="green" font-size="12">48611</text>
<polyline points="1306.24,608.615 1344.44,607.667 1341.83,571.074 1303.76,572.427 1306.24,608.615" fill="none" stroke="green" stroke-width="3" />
<text x="1306.240601" y="608.614990" fill="green" font-size="12">48612</text>
<polyline points="1460.86,603.967 1500.82,602.854 1497.58,565.594 1457.4,567.252 1460.86,603.967" fill="none" stroke="green" stroke-width="3" />
<text x="1460.857666" y="603.967041" fill="green" font-size="12">48614</text>
<polyline points="1388.15,680.365 1427.64,679.63 1424.39,642.253 1385.15,643.142 1388.15,680.365" fill="none" stroke="green" stroke-width="3" />
<text x="1388.146118" y="680.364746" fill="green" font-size="12">48617</text>
<polyline points="1547.08,676.827 1587.98,675.831 1583.96,637.826 1543.5,639.095 1547.08,676.827" fill="none" stroke="green" stroke-width="3" />
<text x="1547.084473" y="676.826904" fill="green" font-size="12">48619</text>
<polyline points="1293.4,397.174 1331.19,394.613 1328.71,359.331 1291.37,362.216 1293.4,397.174" fill="none" stroke="green" stroke-width="3" />
<text x="1293.403809" y="397.174408" fill="green" font-size="12">48600</text>
<polyline points="1443.13,388.179 1482.12,386.911 1479.02,350.824 1440.81,353.366 1443.13,388.179" fill="none" stroke="green" stroke-width="3" />
<text x="1443.130371" y="388.178741" fill="green" font-size="12">48602</text>
<polyline points="1372.4,463.839 1411.64,461.251 1408.59,425.34 1369.88,427.32 1372.4,463.839" fill="none" stroke="green" stroke-width="3" />
<text x="1372.398560" y="463.838928" fill="green" font-size="12">48605</text>
<polyline points="1526.84,455.811 1566.59,454.317 1563.77,416.481 1523.53,419.376 1526.84,455.811" fill="none" stroke="green" stroke-width="3" />
<text x="1526.837891" y="455.811432" fill="green" font-size="12">48607</text>
<polyline points="1302.11,537.349 1340.64,535.987 1338.15,499.382 1299.49,500.602 1302.11,537.349" fill="none" stroke="green" stroke-width="3" />
<text x="1302.109009" y="537.349243" fill="green" font-size="12">48608</text>
<polyline points="1454.54,531.718 1494.85,530.375 1491.63,493.079 1451.51,495.199 1454.54,531.718" fill="none" stroke="green" stroke-width="3" />
<text x="1454.544067" y="531.717834" fill="green" font-size="12">48610</text>
<polyline points="1383.69,606.713 1422.48,605.906 1419.35,568.597 1380.47,569.625 1383.69,606.713" fill="none" stroke="green" stroke-width="3" />
<text x="1383.686401" y="606.712585" fill="green" font-size="12">48613</text>
<polyline points="1540.74,601.987 1580.55,600.764 1576.89,563.217 1537.03,564.14 1540.74,601.987" fill="none" stroke="green" stroke-width="3" />
<text x="1540.743286" y="601.986816" fill="green" font-size="12">48615</text>
<polyline points="1311.35,682.408 1350.5,681.46 1347.78,643.882 1309.22,645.006 1311.35,682.408" fill="none" stroke="green" stroke-width="3" />
<text x="1311.354126" y="682.407532" fill="green" font-size="12">48616</text>
<polyline points="1467.18,679.633 1507.81,677.993 1504.76,640.16 1464.39,641.373 1467.18,679.633" fill="none" stroke="green" stroke-width="3" />
<text x="1467.177856" y="679.632935" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.89131853376
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-1.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1377.59,233.64 1417.54,229.659 1414.2,192.218 1374.62,196.259 1377.59,233.64" fill="none" stroke="green" stroke-width="3" />
<text x="1377.588257" y="233.639587" fill="green" font-size="12">48601</text>
<polyline points="1535.31,218.149 1575.98,214.535 1571.93,177.086 1531.56,180.869 1535.31,218.149" fill="none" stroke="green" stroke-width="3" />
<text x="1535.305908" y="218.149307" fill="green" font-size="12">48603</text>
<polyline points="1306.12,313.841 1345.08,310.326 1341.59,274.213 1303.34,277.205 1306.12,313.841" fill="none" stroke="green" stroke-width="3" />
<text x="1306.116943" y="313.840912" fill="green" font-size="12">48604</text>
<polyline points="1462.41,299.948 1502.63,296.395 1499.19,258.895 1459.29,262.52 1462.41,299.948" fill="none" stroke="green" stroke-width="3" />
<text x="1462.405518" y="299.948456" fill="green" font-size="12">48606</text>
<polyline points="1390.1,380.932 1429.53,377.934 1426.24,340.646 1386.85,344.056 1390.1,380.932" fill="none" stroke="green" stroke-width="3" />
<text x="1390.102661" y="380.931671" fill="green" font-size="12">48609</text>
<polyline points="1549.18,367.838 1588.58,365.236 1584.65,327.663 1546.49,329.953 1549.18,367.838" fill="none" stroke="green" stroke-width="3" />
<text x="1549.179443" y="367.838379" fill="green" font-size="12">48611</text>
<polyline points="1318.51,462.043 1358.46,459.202 1354.72,421.314 1315.22,424.358 1318.51,462.043" fill="none" stroke="green" stroke-width="3" />
<text x="1318.508179" y="462.043243" fill="green" font-size="12">48612</text>
<polyline points="1476.8,449.947 1516.71,447.297 1512.82,409.048 1472.77,412.225 1476.8,449.947" fill="none" stroke="green" stroke-width="3" />
<text x="1476.802612" y="449.946777" fill="green" font-size="12">48614</text>
<polyline points="1404.71,531.414 1445.43,528.575 1441.9,490.051 1400.94,492.917 1404.71,531.414" fill="none" stroke="green" stroke-width="3" />
<text x="1404.714844" y="531.413879" fill="green" font-size="12">48617</text>
<polyline points="1566.05,520.226 1606.48,517.6 1601.71,478.767 1560.93,481.633 1566.05,520.226" fill="none" stroke="green" stroke-width="3" />
<text x="1566.048706" y="520.226074" fill="green" font-size="12">48619</text>
<polyline points="1299.98,243.184 1339.74,239.226 1336.86,201.814 1296.94,205.821 1299.98,243.184" fill="none" stroke="green" stroke-width="3" />
<text x="1299.982056" y="243.184250" fill="green" font-size="12">48600</text>
<polyline points="1456.19,227.932 1496.75,224.579 1493.37,186.521 1452.81,190.511 1456.19,227.932" fill="none" stroke="green" stroke-width="3" />
<text x="1456.190552" y="227.932159" fill="green" font-size="12">48602</text>
<polyline points="1381.08,272.196 1383.98,309.481 1423.91,305.67 1420.3,268.409 1381.08,272.196" fill="none" stroke="green" stroke-width="3" />
<text x="1381.081299" y="272.196045" fill="green" font-size="12">48605</text>
<polyline points="1542.88,294.537 1582.19,292.009 1578.75,254.058 1539.62,256.704 1542.88,294.537" fill="none" stroke="green" stroke-width="3" />
<text x="1542.879883" y="294.537292" fill="green" font-size="12">48607</text>
<polyline points="1312.41,390.445 1352.47,386.979 1349.09,349.085 1309.4,353.059 1312.41,390.445" fill="none" stroke="green" stroke-width="3" />
<text x="1312.406006" y="390.445038" fill="green" font-size="12">48608</text>
<polyline points="1469.6,377.691 1510.82,373.957 1506.69,336.139 1466.97,339.796 1469.6,377.691" fill="none" stroke="green" stroke-width="3" />
<text x="1469.599854" y="377.690796" fill="green" font-size="12">48610</text>
<polyline points="1394.12,420.463 1397.87,459 1438.66,455.776 1434.26,417.358 1394.12,420.463" fill="none" stroke="green" stroke-width="3" />
<text x="1394.115112" y="420.463196" fill="green" font-size="12">48613</text>
<polyline points="1557.11,447.186 1598.87,444.504 1594.43,405.246 1553.89,408.197 1557.11,447.186" fill="none" stroke="green" stroke-width="3" />
<text x="1557.106689" y="447.186432" fill="green" font-size="12">48615</text>
<polyline points="1325.91,539.723 1366.12,537.195 1362.37,498.437 1322.23,501.476 1325.91,539.723" fill="none" stroke="green" stroke-width="3" />
<text x="1325.910889" y="539.723450" fill="green" font-size="12">48616</text>
<polyline points="1485.65,528.902 1527.6,526.066 1523.4,486.462 1481.83,489.707 1485.65,528.902" fill="none" stroke="green" stroke-width="3" />
<text x="1485.648682" y="528.901550" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.12427806234
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-2.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1480.65,85.9842 1536.13,82.8197 1538.86,22.7911 1483.49,26.2682 1480.65,85.9842" fill="none" stroke="green" stroke-width="3" />
<text x="1480.648926" y="85.984230" fill="green" font-size="12">48601</text>
<polyline points="1365.31,209.826 1421.08,206.09 1423,147.409 1367.77,150.873 1365.31,209.826" fill="none" stroke="green" stroke-width="3" />
<text x="1365.312988" y="209.825806" fill="green" font-size="12">48604</text>
<polyline points="1581.29,195.975 1636.13,193.27 1640.51,134.807 1585.92,137.737 1581.29,195.975" fill="none" stroke="green" stroke-width="3" />
<text x="1581.291260" y="195.974930" fill="green" font-size="12">48606</text>
<polyline points="1467.73,311.926 1520.55,308.732 1524.37,254.145 1470.83,257.484 1467.73,311.926" fill="none" stroke="green" stroke-width="3" />
<text x="1467.725464" y="311.925690" fill="green" font-size="12">48609</text>
<polyline points="1678.11,299.656 1728.07,296.963 1733.85,242.453 1684.11,245.028 1678.11,299.656" fill="none" stroke="green" stroke-width="3" />
<text x="1678.112183" y="299.655853" fill="green" font-size="12">48611</text>
<polyline points="1358.84,424.565 1411.06,421.179 1412.72,368.966 1360.27,372.199 1358.84,424.565" fill="none" stroke="green" stroke-width="3" />
<text x="1358.841064" y="424.564758" fill="green" font-size="12">48612</text>
<polyline points="1565.01,411.651 1615.94,408.256 1620.92,355.985 1568.79,358.936 1565.01,411.651" fill="none" stroke="green" stroke-width="3" />
<text x="1565.013916" y="411.650513" fill="green" font-size="12">48614</text>
<polyline points="1456.93,518.885 1508.52,515.552 1511.41,465.146 1459.29,468.313 1456.93,518.885" fill="none" stroke="green" stroke-width="3" />
<text x="1456.933105" y="518.884766" fill="green" font-size="12">48617</text>
<polyline points="1656.81,506.011 1707.05,503.156 1711.7,452.871 1661.05,455.896 1656.81,506.011" fill="none" stroke="green" stroke-width="3" />
<text x="1656.806152" y="506.011230" fill="green" font-size="12">48619</text>
<polyline points="1369.52,92.6488 1426.72,87.9975 1428.33,28.0723 1372.39,30.325 1369.52,92.6488" fill="none" stroke="green" stroke-width="3" />
<text x="1369.518433" y="92.648804" fill="green" font-size="12">48600</text>
<polyline points="1590.64,78.1485 1645.18,75.5008 1650.33,15.4836 1595.3,17.8232 1590.64,78.1485" fill="none" stroke="green" stroke-width="3" />
<text x="1590.636230" y="78.148476" fill="green" font-size="12">48602</text>
<polyline points="1473.29,202.666 1529.04,199.092 1532.44,140.083 1476.36,142.849 1473.29,202.666" fill="none" stroke="green" stroke-width="3" />
<text x="1473.294922" y="202.666061" fill="green" font-size="12">48605</text>
<polyline points="1687.9,188.728 1740.14,186.814 1747.22,127.192 1692.82,129.918 1687.9,188.728" fill="none" stroke="green" stroke-width="3" />
<text x="1687.903442" y="188.728394" fill="green" font-size="12">48607</text>
<polyline points="1361.93,318.369 1415.51,314.445 1418.56,259.148 1363.44,263.838 1361.93,318.369" fill="none" stroke="green" stroke-width="3" />
<text x="1361.929688" y="318.369263" fill="green" font-size="12">48608</text>
<polyline points="1572.5,305.586 1625.16,301.928 1630.32,247.095 1577.11,250.361 1572.5,305.586" fill="none" stroke="green" stroke-width="3" />
<text x="1572.501587" y="305.586060" fill="green" font-size="12">48610</text>
<polyline points="1462.31,417.067 1514.5,414.531 1517.47,361.646 1465.07,364.23 1462.31,417.067" fill="none" stroke="green" stroke-width="3" />
<text x="1462.307617" y="417.067352" fill="green" font-size="12">48613</text>
<polyline points="1666.8,404.402 1716.85,401.537 1721.93,349.596 1672.44,351.307 1666.8,404.402" fill="none" stroke="green" stroke-width="3" />
<text x="1666.799194" y="404.401581" fill="green" font-size="12">48615</text>
<polyline points="1355.68,523.805 1407.25,521.064 1409.44,470.152 1356.13,473.535 1355.68,523.805" fill="none" stroke="green" stroke-width="3" />
<text x="1355.683105" y="523.804565" fill="green" font-size="12">48616</text>
<polyline points="1557.03,511.571 1609.12,507.885 1612.78,457.055 1561.36,460.423 1557.03,511.571" fill="none" stroke="green" stroke-width="3" />
<text x="1557.027588" y="511.571320" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.96923416025
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-3.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1222.11,348.785 1216.37,300.245 1166.46,306.593 1172.06,355.129 1222.11,348.785" fill="none" stroke="green" stroke-width="3" />
<text x="1222.111084" y="348.784912" fill="green" font-size="12">48601</text>
<polyline points="1199.85,158.204 1193.67,110.035 1144,116.397 1149.26,164.909 1199.85,158.204" fill="none" stroke="green" stroke-width="3" />
<text x="1199.847046" y="158.204208" fill="green" font-size="12">48603</text>
<polyline points="1338.62,434.53 1331.86,384.154 1279.36,390.333 1285.77,440.204 1338.62,434.53" fill="none" stroke="green" stroke-width="3" />
<text x="1338.622192" y="434.530487" fill="green" font-size="12">48604</text>
<polyline points="1311.47,240.157 1305.32,190.902 1253.95,197.879 1260.24,246.411 1311.47,240.157" fill="none" stroke="green" stroke-width="3" />
<text x="1311.468262" y="240.157288" fill="green" font-size="12">48606</text>
<polyline points="1428.08,322.549 1420.25,274.269 1368.6,281.004 1375.68,328.877 1428.08,322.549" fill="none" stroke="green" stroke-width="3" />
<text x="1428.077271" y="322.549194" fill="green" font-size="12">48609</text>
<polyline points="1399.74,131.376 1391.64,85.3372 1341.11,91.8847 1348.33,138.087 1399.74,131.376" fill="none" stroke="green" stroke-width="3" />
<text x="1399.739502" y="131.376297" fill="green" font-size="12">48611</text>
<polyline points="1550.77,409.181 1541.71,358.775 1489.09,365.109 1495.86,415.912 1550.77,409.181" fill="none" stroke="green" stroke-width="3" />
<text x="1550.766846" y="409.180939" fill="green" font-size="12">48612</text>
<polyline points="1517.27,213.761 1508.71,165.099 1456.42,171.521 1463.94,220.6 1517.27,213.761" fill="none" stroke="green" stroke-width="3" />
<text x="1517.266602" y="213.760712" fill="green" font-size="12">48614</text>
<polyline points="1639.27,297.008 1629.77,248.022 1577.12,254.516 1586.11,303.228 1639.27,297.008" fill="none" stroke="green" stroke-width="3" />
<text x="1639.266846" y="297.007874" fill="green" font-size="12">48617</text>
<polyline points="1602.3,106.652 1592.92,59.6051 1542.63,65.8528 1550.4,112.725 1602.3,106.652" fill="none" stroke="green" stroke-width="3" />
<text x="1602.301147" y="106.652153" fill="green" font-size="12">48619</text>
<polyline points="1236.49,449.318 1229.8,398.073 1177.8,404.405 1183.69,455.228 1236.49,449.318" fill="none" stroke="green" stroke-width="3" />
<text x="1236.492432" y="449.318146" fill="green" font-size="12">48600</text>
<polyline points="1212.46,253.816 1207.14,204.864 1155.54,211.796 1161.42,260.15 1212.46,253.816" fill="none" stroke="green" stroke-width="3" />
<text x="1212.459473" y="253.815598" fill="green" font-size="12">48602</text>
<polyline points="1325.86,337.833 1318.71,289.046 1267.29,295.762 1274.16,344.212 1325.86,337.833" fill="none" stroke="green" stroke-width="3" />
<text x="1325.864990" y="337.833160" fill="green" font-size="12">48605</text>
<polyline points="1301.37,146.699 1294.98,99.184 1244.21,105.125 1249.89,152.637 1301.37,146.699" fill="none" stroke="green" stroke-width="3" />
<text x="1301.373169" y="146.699203" fill="green" font-size="12">48607</text>
<polyline points="1445.37,424.986 1437.86,373.319 1384.36,379.553 1391.05,431.454 1445.37,424.986" fill="none" stroke="green" stroke-width="3" />
<text x="1445.368042" y="424.986145" fill="green" font-size="12">48608</text>
<polyline points="1415.36,229.485 1408.3,180.035 1355.68,186.583 1362.75,235.348 1415.36,229.485" fill="none" stroke="green" stroke-width="3" />
<text x="1415.355225" y="229.484650" fill="green" font-size="12">48610</text>
<polyline points="1535.19,311.401 1525.94,263.202 1472.87,269.811 1482.18,317.866 1535.19,311.401" fill="none" stroke="green" stroke-width="3" />
<text x="1535.192505" y="311.400970" fill="green" font-size="12">48613</text>
<polyline points="1503.44,121.381 1494.25,74.7291 1443.12,81.2754 1450.7,127.522 1503.44,121.381" fill="none" stroke="green" stroke-width="3" />
<text x="1503.442139" y="121.380783" fill="green" font-size="12">48615</text>
<polyline points="1659.89,399.384 1649.84,348.796 1596,354.982 1604.8,406.215 1659.89,399.384" fill="none" stroke="green" stroke-width="3" />
<text x="1659.892212" y="399.384186" fill="green" font-size="12">48616</text>
<polyline points="1622.02,204.145 1613.07,154.467 1560.33,160.729 1568.57,210.357 1622.02,204.145" fill="none" stroke="green" stroke-width="3" />
<text x="1622.018433" y="204.144791" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.60197092768
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-4.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1161.82,600.762 1163.24,562.024 1120.93,563.719 1120.48,602.199 1161.82,600.762" fill="none" stroke="green" stroke-width="3" />
<text x="1161.815552" y="600.761658" fill="green" font-size="12">48601</text>
<polyline points="1167.4,439.41 1168.94,395.168 1123.94,397.177 1122.79,441.483 1167.4,439.41" fill="none" stroke="green" stroke-width="3" />
<text x="1167.404541" y="439.410339" fill="green" font-size="12">48603</text>
<polyline points="1241.05,672.531 1243.32,635.811 1201.96,636.943 1200.22,673.816 1241.05,672.531" fill="none" stroke="green" stroke-width="3" />
<text x="1241.052490" y="672.530945" fill="green" font-size="12">48604</text>
<polyline points="1250.24,519.469 1253.13,477.784 1208.7,479.424 1206.81,521.516 1250.24,519.469" fill="none" stroke="green" stroke-width="3" />
<text x="1250.237061" y="519.468994" fill="green" font-size="12">48606</text>
<polyline points="1329.27,595.172 1332.63,555.745 1289.95,557.359 1286.86,596.405 1329.27,595.172" fill="none" stroke="green" stroke-width="3" />
<text x="1329.272949" y="595.172302" fill="green" font-size="12">48609</text>
<polyline points="1345.42,431.92 1348.67,386.653 1303.43,388.489 1300.43,433.823 1345.42,431.92" fill="none" stroke="green" stroke-width="3" />
<text x="1345.424316" y="431.919800" fill="green" font-size="12">48611</text>
<polyline points="1405.2,668.071 1409.6,630.439 1367.86,631.949 1363.37,668.476 1405.2,668.071" fill="none" stroke="green" stroke-width="3" />
<text x="1405.200684" y="668.071045" fill="green" font-size="12">48612</text>
<polyline points="1424.6,512.735 1429.51,470.11 1384.81,472.208 1379.89,514.238 1424.6,512.735" fill="none" stroke="green" stroke-width="3" />
<text x="1424.596436" y="512.734863" fill="green" font-size="12">48614</text>
<polyline points="1500.18,589.614 1506.08,549.731 1462.4,551.368 1457.02,590.926 1500.18,589.614" fill="none" stroke="green" stroke-width="3" />
<text x="1500.176636" y="589.614075" fill="green" font-size="12">48617</text>
<polyline points="1525.06,423.736 1531.93,378.371 1485.98,380.417 1479.56,425.79 1525.06,423.736" fill="none" stroke="green" stroke-width="3" />
<text x="1525.058838" y="423.735840" fill="green" font-size="12">48619</text>
<polyline points="1157.73,676.412 1159.24,639.123 1118.03,639.842 1117.27,677.301 1157.73,676.412" fill="none" stroke="green" stroke-width="3" />
<text x="1157.728149" y="676.412109" fill="green" font-size="12">48600</text>
<polyline points="1163.27,522.951 1164.35,480.564 1119.99,481.755 1119.64,524.188 1163.27,522.951" fill="none" stroke="green" stroke-width="3" />
<text x="1163.265625" y="522.951355" fill="green" font-size="12">48602</text>
<polyline points="1201.27,599.938 1243.42,599.076 1245.84,560.111 1203.13,561.096 1201.27,599.938" fill="none" stroke="green" stroke-width="3" />
<text x="1201.270752" y="599.937561" fill="green" font-size="12">48605</text>
<polyline points="1254.38,435.44 1256.47,390.93 1211.25,392.006 1208.93,436.124 1254.38,435.44" fill="none" stroke="green" stroke-width="3" />
<text x="1254.376343" y="435.440247" fill="green" font-size="12">48607</text>
<polyline points="1320.73,671.877 1324.38,634.33 1282.55,635.446 1278.99,673.79 1320.73,671.877" fill="none" stroke="green" stroke-width="3" />
<text x="1320.725586" y="671.876770" fill="green" font-size="12">48608</text>
<polyline points="1335.12,517.578 1339.2,475.335 1294.03,476.139 1290.77,518.369 1335.12,517.578" fill="none" stroke="green" stroke-width="3" />
<text x="1335.116821" y="517.577820" fill="green" font-size="12">48610</text>
<polyline points="1369.9,595.453 1413.16,593.947 1417.28,554.43 1373.91,555.237 1369.9,595.453" fill="none" stroke="green" stroke-width="3" />
<text x="1369.902954" y="595.453003" fill="green" font-size="12">48613</text>
<polyline points="1433.58,429.079 1438.58,383.783 1391.77,385.845 1387.74,430.044 1433.58,429.079" fill="none" stroke="green" stroke-width="3" />
<text x="1433.579224" y="429.078918" fill="green" font-size="12">48615</text>
<polyline points="1487.4,667.221 1492.82,629.765 1450.28,631.479 1444.67,668.2 1487.4,667.221" fill="none" stroke="green" stroke-width="3" />
<text x="1487.397583" y="667.221069" fill="green" font-size="12">48616</text>
<polyline points="1510.94,511.321 1517.89,468.175 1472.14,469.854 1465.75,512.261 1510.94,511.321" fill="none" stroke="green" stroke-width="3" />
<text x="1510.942993" y="511.321289" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.01227215325
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-5.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="961.526,180.89 998.663,173.187 994.492,137.17 957.514,145.294 961.526,180.89" fill="none" stroke="green" stroke-width="3" />
<text x="961.526062" y="180.890030" fill="green" font-size="12">48601</text>
<polyline points="1111.38,149.231 1150.94,141.91 1145.98,104.73 1106.94,113.302 1111.38,149.231" fill="none" stroke="green" stroke-width="3" />
<text x="1111.380981" y="149.230835" fill="green" font-size="12">48603</text>
<polyline points="897.504,265.618 933.629,258.776 929.834,223.057 893.547,230.007 897.504,265.618" fill="none" stroke="green" stroke-width="3" />
<text x="897.504028" y="265.617676" fill="green" font-size="12">48604</text>
<polyline points="1044.22,237.68 1082.99,230.329 1078.23,193.237 1039.66,200.734 1044.22,237.68" fill="none" stroke="green" stroke-width="3" />
<text x="1044.215210" y="237.679565" fill="green" font-size="12">48606</text>
<polyline points="978.373,323.581 1015.69,317.462 1011.31,280.87 973.993,287.962 978.373,323.581" fill="none" stroke="green" stroke-width="3" />
<text x="978.372559" y="323.581116" fill="green" font-size="12">48609</text>
<polyline points="1130.85,296.856 1170.36,290.62 1165.28,253.041 1125.9,259.465 1130.85,296.856" fill="none" stroke="green" stroke-width="3" />
<text x="1130.848511" y="296.855865" fill="green" font-size="12">48611</text>
<polyline points="912.622,409.819 949.752,403.973 945.61,366.796 909.083,373.39 912.622,409.819" fill="none" stroke="green" stroke-width="3" />
<text x="912.621643" y="409.819275" fill="green" font-size="12">48612</text>
<polyline points="1062.53,385.34 1101.74,378.891 1096.73,341.298 1058.06,348.126 1062.53,385.34" fill="none" stroke="green" stroke-width="3" />
<text x="1062.534424" y="385.340088" fill="green" font-size="12">48614</text>
<polyline points="994.766,472.561 1033.85,466.87 1029.12,428.338 990.725,434.344 994.766,472.561" fill="none" stroke="green" stroke-width="3" />
<text x="994.765564" y="472.561249" fill="green" font-size="12">48617</text>
<polyline points="1150.67,449.554 1191.84,443.556 1186.21,404.371 1145.66,410.473 1150.67,449.554" fill="none" stroke="green" stroke-width="3" />
<text x="1150.667725" y="449.554413" fill="green" font-size="12">48619</text>
<polyline points="889.985,199.787 926.488,191.674 922.555,156.222 886.374,163.982 889.985,199.787" fill="none" stroke="green" stroke-width="3" />
<text x="889.984741" y="199.787430" fill="green" font-size="12">48600</text>
<polyline points="1034.97,168.698 1073.74,160.712 1068.65,124.181 1030.37,132.357 1034.97,168.698" fill="none" stroke="green" stroke-width="3" />
<text x="1034.971924" y="168.697723" fill="green" font-size="12">48602</text>
<polyline points="1007.71,248.093 1003.32,211.708 965.542,219.252 970.112,255.544 1007.71,248.093" fill="none" stroke="green" stroke-width="3" />
<text x="1007.705933" y="248.093491" fill="green" font-size="12">48605</text>
<polyline points="1120.36,225.086 1160.32,218.317 1155.17,180.507 1115.31,187.178 1120.36,225.086" fill="none" stroke="green" stroke-width="3" />
<text x="1120.361816" y="225.086212" fill="green" font-size="12">48607</text>
<polyline points="906.624,340.189 942.87,333.021 938.392,297.048 902.169,304.013 906.624,340.189" fill="none" stroke="green" stroke-width="3" />
<text x="906.624146" y="340.189362" fill="green" font-size="12">48608</text>
<polyline points="1053.66,313.242 1092.29,306.299 1087.53,269.16 1048.9,276.496 1053.66,313.242" fill="none" stroke="green" stroke-width="3" />
<text x="1053.658569" y="313.241547" fill="green" font-size="12">48610</text>
<polyline points="1026.17,393.921 1021.38,356.461 983.373,362.746 987.669,399.949 1026.17,393.921" fill="none" stroke="green" stroke-width="3" />
<text x="1026.171143" y="393.921082" fill="green" font-size="12">48613</text>
<polyline points="1141.12,373.867 1181.45,367.684 1175.56,329.788 1136.04,335.906 1141.12,373.867" fill="none" stroke="green" stroke-width="3" />
<text x="1141.118408" y="373.867371" fill="green" font-size="12">48615</text>
<polyline points="922.38,485.614 960.985,480.247 955.976,441.965 918.181,447.772 922.38,485.614" fill="none" stroke="green" stroke-width="3" />
<text x="922.379578" y="485.613617" fill="green" font-size="12">48616</text>
<polyline points="1073,463.024 1113.5,456.693 1107.94,417.233 1068.06,423.802 1073,463.024" fill="none" stroke="green" stroke-width="3" />
<text x="1073.001709" y="463.023590" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.0423236365
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-6.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="973.478,90.7454 1019.58,88.3579 1018.22,35.5119 971.393,38.0315 973.478,90.7454" fill="none" stroke="green" stroke-width="3" />
<text x="973.477661" y="90.745377" fill="green" font-size="12">48601</text>
<polyline points="1156.18,80.3913 1202.45,77.7942 1204.51,25.9644 1158.14,27.9488 1156.18,80.3913" fill="none" stroke="green" stroke-width="3" />
<text x="1156.181641" y="80.391281" fill="green" font-size="12">48603</text>
<polyline points="889.397,195.436 934.235,192.825 931.088,143.462 885.473,146.002 889.397,195.436" fill="none" stroke="green" stroke-width="3" />
<text x="889.396729" y="195.435806" fill="green" font-size="12">48604</text>
<polyline points="1065.12,184.975 1109.74,182.464 1110.23,133.209 1065.1,135.902 1065.12,184.975" fill="none" stroke="green" stroke-width="3" />
<text x="1065.120605" y="184.974594" fill="green" font-size="12">48606</text>
<polyline points="981.455,281.021 1023.61,278.444 1022.98,233.625 979.548,236.218 981.455,281.021" fill="none" stroke="green" stroke-width="3" />
<text x="981.454956" y="281.020996" fill="green" font-size="12">48609</text>
<polyline points="1150.32,270.641 1191.79,267.688 1194.59,222.833 1151.83,226.033 1150.32,270.641" fill="none" stroke="green" stroke-width="3" />
<text x="1150.322266" y="270.640564" fill="green" font-size="12">48611</text>
<polyline points="903.591,370.807 944.803,368.034 941.782,326.576 900.361,329.095 903.591,370.807" fill="none" stroke="green" stroke-width="3" />
<text x="903.591309" y="370.806976" fill="green" font-size="12">48612</text>
<polyline points="1066.02,360.52 1107.08,357.742 1107.17,316.263 1066.42,318.74 1066.02,360.52" fill="none" stroke="green" stroke-width="3" />
<text x="1066.020996" y="360.519623" fill="green" font-size="12">48614</text>
<polyline points="987.993,444.139 1027.96,441.847 1026.91,402.713 987.215,405.585 987.993,444.139" fill="none" stroke="green" stroke-width="3" />
<text x="987.993103" y="444.138885" fill="green" font-size="12">48617</text>
<polyline points="1144.6,433.874 1183.83,430.97 1185.66,391.943 1146.12,394.862 1144.6,433.874" fill="none" stroke="green" stroke-width="3" />
<text x="1144.602783" y="433.873840" fill="green" font-size="12">48619</text>
<polyline points="879.565,98.8311 926.215,95.174 922.728,41.9485 875.174,44.9588 879.565,98.8311" fill="none" stroke="green" stroke-width="3" />
<text x="879.565063" y="98.831100" fill="green" font-size="12">48600</text>
<polyline points="1062.45,87.6651 1108.79,85.0553 1109.04,31.7388 1062.93,34.4441 1062.45,87.6651" fill="none" stroke="green" stroke-width="3" />
<text x="1062.445923" y="87.665062" fill="green" font-size="12">48602</text>
<polyline points="973.271,143.106 975.749,192.658 1021.54,190.782 1018.92,140.877 973.271,143.106" fill="none" stroke="green" stroke-width="3" />
<text x="973.270996" y="143.105530" fill="green" font-size="12">48605</text>
<polyline points="1150.81,180.724 1195.43,177.985 1197.8,127.599 1151.8,131.887 1150.81,180.724" fill="none" stroke="green" stroke-width="3" />
<text x="1150.805542" y="180.724335" fill="green" font-size="12">48607</text>
<polyline points="895.314,289.226 938.358,286.46 935.249,240.887 891.718,243.977 895.314,289.226" fill="none" stroke="green" stroke-width="3" />
<text x="895.314270" y="289.225830" fill="green" font-size="12">48608</text>
<polyline points="1064.24,278.831 1106.52,275.831 1107.61,230.559 1063.49,233.553 1064.24,278.831" fill="none" stroke="green" stroke-width="3" />
<text x="1064.236572" y="278.830505" fill="green" font-size="12">48610</text>
<polyline points="982.016,326.395 984.393,368.503 1025.03,366.2 1023.77,323.807 982.016,326.395" fill="none" stroke="green" stroke-width="3" />
<text x="982.015869" y="326.394714" fill="green" font-size="12">48613</text>
<polyline points="1146.14,356.945 1186.64,354.646 1188.53,312.808 1147.28,314.565 1146.14,356.945" fill="none" stroke="green" stroke-width="3" />
<text x="1146.137329" y="356.945221" fill="green" font-size="12">48615</text>
<polyline points="908.726,452.526 949.157,450.607 946.694,410.507 905.706,413.912 908.726,452.526" fill="none" stroke="green" stroke-width="3" />
<text x="908.725525" y="452.526123" fill="green" font-size="12">48616</text>
<polyline points="1065.63,441.997 1105.94,439.001 1105.52,399.376 1065.62,402.341 1065.63,441.997" fill="none" stroke="green" stroke-width="3" />
<text x="1065.630981" y="441.996979" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.41663092406
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-7.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="930.949,336.128 970.724,329.257 967.532,303.302 928.905,310.056 930.949,336.128" fill="none" stroke="green" stroke-width="3" />
<text x="930.948975" y="336.128265" fill="green" font-size="12">48601</text>
<polyline points="1091.46,309.351 1132.33,302.97 1125.3,276.903 1085.33,283.652 1091.46,309.351" fill="none" stroke="green" stroke-width="3" />
<text x="1091.457397" y="309.351135" fill="green" font-size="12">48603</text>
<polyline points="853.659,405.51 894.607,398.498 893.468,369.617 852.656,376.193 853.659,405.51" fill="none" stroke="green" stroke-width="3" />
<text x="853.658752" y="405.510284" fill="green" font-size="12">48604</text>
<polyline points="1020.03,380.388 1062.75,374.629 1056.75,344.84 1015.53,351.817 1020.03,380.388" fill="none" stroke="green" stroke-width="3" />
<text x="1020.033813" y="380.388397" fill="green" font-size="12">48606</text>
<polyline points="941.885,454.018 986.398,446.855 982.146,415.507 938.896,422.11 941.885,454.018" fill="none" stroke="green" stroke-width="3" />
<text x="941.884705" y="454.018036" fill="green" font-size="12">48609</text>
<polyline points="1119.2,430.998 1164.85,424.474 1155.94,393.054 1111.96,398.352 1119.2,430.998" fill="none" stroke="green" stroke-width="3" />
<text x="1119.195923" y="430.997711" fill="green" font-size="12">48611</text>
<polyline points="855.905,537.082 902.737,530.845 900.828,494.607 855.529,502.06 855.905,537.082" fill="none" stroke="green" stroke-width="3" />
<text x="855.905457" y="537.082336" fill="green" font-size="12">48612</text>
<polyline points="1041.35,509.092 1089.7,502.621 1082.03,467.625 1035.66,473.14 1041.35,509.092" fill="none" stroke="green" stroke-width="3" />
<text x="1041.345215" y="509.091980" fill="green" font-size="12">48614</text>
<polyline points="955.284,598.862 1005.15,591.779 999.933,552.092 951.71,559.679 955.284,598.862" fill="none" stroke="green" stroke-width="3" />
<text x="955.283936" y="598.861938" fill="green" font-size="12">48617</text>
<polyline points="1155.16,570.688 1206.05,564.145 1194.97,525.254 1145.05,531.716 1155.16,570.688" fill="none" stroke="green" stroke-width="3" />
<text x="1155.157227" y="570.688110" fill="green" font-size="12">48619</text>
<polyline points="850.153,347.147 890.231,340.158 888.217,313.861 849.431,320.008 850.153,347.147" fill="none" stroke="green" stroke-width="3" />
<text x="850.153198" y="347.147217" fill="green" font-size="12">48600</text>
<polyline points="1009.68,321.059 1050.36,314.884 1045.06,288.546 1005.12,295.252 1009.68,321.059" fill="none" stroke="green" stroke-width="3" />
<text x="1009.680237" y="321.058594" fill="green" font-size="12">48602</text>
<polyline points="932.092,362.031 934.828,391.16 977.715,384.745 973.484,355.744 932.092,362.031" fill="none" stroke="green" stroke-width="3" />
<text x="932.091919" y="362.031342" fill="green" font-size="12">48605</text>
<polyline points="1103.99,365.027 1147.3,359.806 1139.06,329.696 1097.29,335.698 1103.99,365.027" fill="none" stroke="green" stroke-width="3" />
<text x="1103.990112" y="365.026520" fill="green" font-size="12">48607</text>
<polyline points="853.459,466.811 898.051,459.668 895.612,426.744 852.913,433.881 853.459,466.811" fill="none" stroke="green" stroke-width="3" />
<text x="853.459473" y="466.811462" fill="green" font-size="12">48608</text>
<polyline points="1029.29,440.778 1074.8,434.456 1068.16,402.347 1023.87,408.415 1029.29,440.778" fill="none" stroke="green" stroke-width="3" />
<text x="1029.286255" y="440.778168" fill="green" font-size="12">48610</text>
<polyline points="943.878,485.345 947.117,521.778 995.351,515.521 990.469,478.575 943.878,485.345" fill="none" stroke="green" stroke-width="3" />
<text x="943.878113" y="485.345337" fill="green" font-size="12">48613</text>
<polyline points="1135.34,495.411 1184.02,489.054 1173.78,453.439 1126.53,459.801 1135.34,495.411" fill="none" stroke="green" stroke-width="3" />
<text x="1135.341919" y="495.410980" fill="green" font-size="12">48615</text>
<polyline points="856.711,611.316 906.285,605.007 904.167,565.118 855.684,571.842 856.711,611.316" fill="none" stroke="green" stroke-width="3" />
<text x="856.710999" y="611.316040" fill="green" font-size="12">48616</text>
<polyline points="1054.05,584.49 1104.97,577.226 1096.61,537.481 1047.28,544.291 1054.05,584.49" fill="none" stroke="green" stroke-width="3" />
<text x="1054.046997" y="584.490234" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.7736504896
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-8.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="617.968,158.738 672.279,157.611 666.108,108.714 612.278,108.921 617.968,158.738" fill="none" stroke="green" stroke-width="3" />
<text x="617.967773" y="158.737991" fill="green" font-size="12">48601</text>
<polyline points="822.704,157.752 871.943,155.121 865.329,109.701 816.837,109.685 822.704,157.752" fill="none" stroke="green" stroke-width="3" />
<text x="822.703674" y="157.752472" fill="green" font-size="12">48603</text>
<polyline points="518.562,260.514 575.345,258.715 570.413,207.434 512.823,209.008 518.562,260.514" fill="none" stroke="green" stroke-width="3" />
<text x="518.562195" y="260.513550" fill="green" font-size="12">48604</text>
<polyline points="735.211,254.415 786.412,252.762 780.482,204.829 728.771,205.129 735.211,254.415" fill="none" stroke="green" stroke-width="3" />
<text x="735.210571" y="254.415009" fill="green" font-size="12">48606</text>
<polyline points="641.713,356.746 695.351,354.275 689.092,304.539 635.63,306.659 641.713,356.746" fill="none" stroke="green" stroke-width="3" />
<text x="641.712585" y="356.745972" fill="green" font-size="12">48609</text>
<polyline points="847.957,344.39 895.766,342.601 889.634,295.359 841.706,296.65 847.957,344.39" fill="none" stroke="green" stroke-width="3" />
<text x="847.957031" y="344.389862" fill="green" font-size="12">48611</text>
<polyline points="541.065,468.426 599.424,463.54 593.043,411.102 535.536,415.271 541.065,468.426" fill="none" stroke="green" stroke-width="3" />
<text x="541.064819" y="468.426208" fill="green" font-size="12">48612</text>
<polyline points="759.733,450.327 812.033,445.965 805.214,396.167 753.646,400.271 759.733,450.327" fill="none" stroke="green" stroke-width="3" />
<text x="759.732910" y="450.327362" fill="green" font-size="12">48614</text>
<polyline points="665.526,561.614 720.573,555.544 714.737,504.023 659.297,509.377 665.526,561.614" fill="none" stroke="green" stroke-width="3" />
<text x="665.525635" y="561.614380" fill="green" font-size="12">48617</text>
<polyline points="873.2,539.353 923.237,534.105 916.228,484.7 866.586,489.291 873.2,539.353" fill="none" stroke="green" stroke-width="3" />
<text x="873.199768" y="539.352783" fill="green" font-size="12">48619</text>
<polyline points="508.57,161.554 566.257,161.075 560.64,109.519 502.976,109.487 508.57,161.554" fill="none" stroke="green" stroke-width="3" />
<text x="508.569702" y="161.553513" fill="green" font-size="12">48600</text>
<polyline points="723.971,159.44 776.209,159.77 769.577,110.807 717.985,110.36 723.971,159.44" fill="none" stroke="green" stroke-width="3" />
<text x="723.971497" y="159.439575" fill="green" font-size="12">48602</text>
<polyline points="680.18,207.697 624.8,208.208 631.001,259.087 685.843,257.849 680.18,207.697" fill="none" stroke="green" stroke-width="3" />
<text x="680.179504" y="207.696640" fill="green" font-size="12">48605</text>
<polyline points="835.555,251.462 884.879,251.209 878.427,202.746 829.21,203.881 835.555,251.462" fill="none" stroke="green" stroke-width="3" />
<text x="835.554993" y="251.461700" fill="green" font-size="12">48607</text>
<polyline points="531.402,365.236 588.602,361.786 581.787,310.172 524.964,312.933 531.402,365.236" fill="none" stroke="green" stroke-width="3" />
<text x="531.402344" y="365.235870" fill="green" font-size="12">48608</text>
<polyline points="749.381,353.553 799.943,350.367 793.67,301.761 742.782,304.533 749.381,353.553" fill="none" stroke="green" stroke-width="3" />
<text x="749.380554" y="353.552917" fill="green" font-size="12">48610</text>
<polyline points="704.556,405.732 649.145,409.02 654.927,461.28 711.184,457.207 704.556,405.732" fill="none" stroke="green" stroke-width="3" />
<text x="704.556458" y="405.732422" fill="green" font-size="12">48613</text>
<polyline points="860.786,443.784 911.163,440.626 903.89,391.646 854.757,393.964 860.786,443.784" fill="none" stroke="green" stroke-width="3" />
<text x="860.786133" y="443.784180" fill="green" font-size="12">48615</text>
<polyline points="553.941,575.834 612.32,569.507 606.886,516.176 547.775,522.218 553.941,575.834" fill="none" stroke="green" stroke-width="3" />
<text x="553.940918" y="575.834351" fill="green" font-size="12">48616</text>
<polyline points="773.32,551.863 825.849,545.706 819.72,494.74 766.975,500.167 773.32,551.863" fill="none" stroke="green" stroke-width="3" />
<text x="773.319641" y="551.862793" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 3.33980752481
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-9.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="331.796,179.575 398.035,189.569 395.757,129.765 330.483,118.607 331.796,179.575" fill="none" stroke="green" stroke-width="3" />
<text x="331.795715" y="179.574631" fill="green" font-size="12">48601</text>
<polyline points="569.365,215.626 621.879,224.079 623.512,171.88 570.107,161.631 569.365,215.626" fill="none" stroke="green" stroke-width="3" />
<text x="569.365417" y="215.626068" fill="green" font-size="12">48603</text>
<polyline points="198.914,282.412 268.121,288.495 267.338,229.509 195.165,221.004 198.914,282.412" fill="none" stroke="green" stroke-width="3" />
<text x="198.913910" y="282.412262" fill="green" font-size="12">48604</text>
<polyline points="457.602,306.475 514.791,312.369 514.794,260.056 457.519,252.764 457.602,306.475" fill="none" stroke="green" stroke-width="3" />
<text x="457.602051" y="306.474640" fill="green" font-size="12">48606</text>
<polyline points="338.808,404.953 400.323,407.798 398.998,355.028 336.651,350.535 338.808,404.953" fill="none" stroke="green" stroke-width="3" />
<text x="338.807770" y="404.953491" fill="green" font-size="12">48609</text>
<polyline points="566.986,416.086 617.135,418.671 617.892,371.553 567.347,367.559 566.986,416.086" fill="none" stroke="green" stroke-width="3" />
<text x="566.986328" y="416.086365" fill="green" font-size="12">48611</text>
<polyline points="212.856,511.161 280.776,510.973 278.63,457.284 209.694,456.002 212.856,511.161" fill="none" stroke="green" stroke-width="3" />
<text x="212.855713" y="511.161255" fill="green" font-size="12">48612</text>
<polyline points="459.367,509.293 514.244,509.179 514.504,461.733 459.173,460.669 459.367,509.293" fill="none" stroke="green" stroke-width="3" />
<text x="459.366730" y="509.293365" fill="green" font-size="12">48614</text>
<polyline points="345.979,609.103 405.024,605.901 403.759,558.341 344.48,560.164 345.979,609.103" fill="none" stroke="green" stroke-width="3" />
<text x="345.979401" y="609.102905" fill="green" font-size="12">48617</text>
<polyline points="563.161,597.582 610.9,594.896 611.962,552.58 564.201,553.876 563.161,597.582" fill="none" stroke="green" stroke-width="3" />
<text x="563.161377" y="597.582275" fill="green" font-size="12">48619</text>
<polyline points="189.934,153.998 264.651,164.868 262.333,100.89 186.154,87.7557 189.934,153.998" fill="none" stroke="green" stroke-width="3" />
<text x="189.934280" y="153.998489" fill="green" font-size="12">48600</text>
<polyline points="455.992,194.898 516.006,204.447 517.363,148.153 456.641,137.074 455.992,194.898" fill="none" stroke="green" stroke-width="3" />
<text x="455.991943" y="194.898392" fill="green" font-size="12">48602</text>
<polyline points="397.465,297.088 397.123,241.078 331.988,232.474 333.097,290.031 397.465,297.088" fill="none" stroke="green" stroke-width="3" />
<text x="397.465179" y="297.087921" fill="green" font-size="12">48605</text>
<polyline points="567.306,315.168 617.386,319.512 620.054,271.186 568.263,263.97 567.306,315.168" fill="none" stroke="green" stroke-width="3" />
<text x="567.305542" y="315.167755" fill="green" font-size="12">48607</text>
<polyline points="202.025,393.381 272.37,397.377 269.13,341.367 198.806,335.072 202.025,393.381" fill="none" stroke="green" stroke-width="3" />
<text x="202.024750" y="393.381042" fill="green" font-size="12">48608</text>
<polyline points="457.867,407.818 514.041,410.63 514.124,360.507 457.134,355.766 457.867,407.818" fill="none" stroke="green" stroke-width="3" />
<text x="457.866730" y="407.818268" fill="green" font-size="12">48610</text>
<polyline points="402.016,506.21 401.382,455.519 338.221,453.206 339.82,505.708 402.016,506.21" fill="none" stroke="green" stroke-width="3" />
<text x="402.015625" y="506.210236" fill="green" font-size="12">48613</text>
<polyline points="563.043,506.113 612.937,506.487 613.699,460.625 563.893,459.445 563.043,506.113" fill="none" stroke="green" stroke-width="3" />
<text x="563.043274" y="506.112549" fill="green" font-size="12">48615</text>
<polyline points="215.949,610.146 282.119,607.427 278.762,556.716 212.549,558.182 215.949,610.146" fill="none" stroke="green" stroke-width="3" />
<text x="215.949295" y="610.146484" fill="green" font-size="12">48616</text>
<polyline points="458.576,599.804 511.78,597.28 512.143,551.942 458.492,553.418 458.576,599.804" fill="none" stroke="green" stroke-width="3" />
<text x="458.575623" y="599.804138" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.30152949436
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-10.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="222.523,260.372 216.912,217.635 174.018,221.707 181.275,263.783 222.523,260.372" fill="none" stroke="green" stroke-width="3" />
<text x="222.522720" y="260.372314" fill="green" font-size="12">48601</text>
<polyline points="197.28,89.311 187.799,43.7878 145.962,47.1627 153.748,92.1406 197.28,89.311" fill="none" stroke="green" stroke-width="3" />
<text x="197.280319" y="89.311028" fill="green" font-size="12">48603</text>
<polyline points="317.014,337.112 311.372,295.127 269.805,298.668 276.05,340.646 317.014,337.112" fill="none" stroke="green" stroke-width="3" />
<text x="317.013885" y="337.112396" fill="green" font-size="12">48604</text>
<polyline points="295.508,169.239 289.733,124.955 245.201,128.285 251.416,172.433 295.508,169.239" fill="none" stroke="green" stroke-width="3" />
<text x="295.507935" y="169.239349" fill="green" font-size="12">48606</text>
<polyline points="389.96,246.367 384.329,203.367 341.378,206.95 347.696,249.611 389.96,246.367" fill="none" stroke="green" stroke-width="3" />
<text x="389.959595" y="246.366608" fill="green" font-size="12">48609</text>
<polyline points="366.48,74.5726 360.948,32.7228 317.286,34.8362 324.416,77.9818 366.48,74.5726" fill="none" stroke="green" stroke-width="3" />
<text x="366.480438" y="74.572601" fill="green" font-size="12">48611</text>
<polyline points="484.815,323.148 479.275,281.422 436.59,284.787 443.134,326.351 484.815,323.148" fill="none" stroke="green" stroke-width="3" />
<text x="484.815125" y="323.147705" fill="green" font-size="12">48612</text>
<polyline points="463.89,155.441 457.598,110.989 414.331,114.292 420.063,158.543 463.89,155.441" fill="none" stroke="green" stroke-width="3" />
<text x="463.889557" y="155.440750" fill="green" font-size="12">48614</text>
<polyline points="557.536,233.393 551.556,189.926 509.016,193.278 514.665,236.345 557.536,233.393" fill="none" stroke="green" stroke-width="3" />
<text x="557.535583" y="233.393188" fill="green" font-size="12">48617</text>
<polyline points="535.22,60.7091 529.013,17.2774 487.738,20.1942 492.589,64.0113 535.22,60.7091" fill="none" stroke="green" stroke-width="3" />
<text x="535.220459" y="60.709080" fill="green" font-size="12">48619</text>
<polyline points="209.138,172.819 202.463,127.248 158.11,131.195 165.383,176.04 209.138,172.819" fill="none" stroke="green" stroke-width="3" />
<text x="209.137878" y="172.819244" fill="green" font-size="12">48602</text>
<polyline points="261.948,254.224 304.561,250.986 299.075,207.864 256.2,211.195 261.948,254.224" fill="none" stroke="green" stroke-width="3" />
<text x="261.948456" y="254.223755" fill="green" font-size="12">48605</text>
<polyline points="280.276,78.5277 273.482,34.8403 230.918,37.4325 237.351,81.8099 280.276,78.5277" fill="none" stroke="green" stroke-width="3" />
<text x="280.276367" y="78.527657" fill="green" font-size="12">48607</text>
<polyline points="398.571,327.622 393.539,285.167 350.829,288.531 356.646,330.593 398.571,327.622" fill="none" stroke="green" stroke-width="3" />
<text x="398.570862" y="327.621948" fill="green" font-size="12">48608</text>
<polyline points="378.839,160.236 372.627,115.519 328.745,119.236 334.531,162.976 378.839,160.236" fill="none" stroke="green" stroke-width="3" />
<text x="378.838562" y="160.236038" fill="green" font-size="12">48610</text>
<polyline points="429.17,240.374 472.259,237.323 467.007,194.252 423.7,197.54 429.17,240.374" fill="none" stroke="green" stroke-width="3" />
<text x="429.169769" y="240.373611" fill="green" font-size="12">48613</text>
<polyline points="449.749,65.4532 443.392,21.9607 402.644,25.9096 406.869,68.6769 449.749,65.4532" fill="none" stroke="green" stroke-width="3" />
<text x="449.748932" y="65.453217" fill="green" font-size="12">48615</text>
<polyline points="565.843,314.411 560.579,272.552 518.264,275.53 524.113,317.545 565.843,314.411" fill="none" stroke="green" stroke-width="3" />
<text x="565.842590" y="314.410583" fill="green" font-size="12">48616</text>
<polyline points="545.751,146.685 538.839,101.83 496.324,105.396 501.664,149.68 545.751,146.685" fill="none" stroke="green" stroke-width="3" />
<text x="545.750671" y="146.685135" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.70201751052
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-11.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="109.224,440.647 102.671,390.23 35.9776,389.302 40.6165,440.269 109.224,440.647" fill="none" stroke="green" stroke-width="3" />
<text x="109.223740" y="440.646667" fill="green" font-size="12">48601</text>
<polyline points="89.1455,245.274 86.6879,196.433 16.7397,188.122 21.451,238.642 89.1455,245.274" fill="none" stroke="green" stroke-width="3" />
<text x="89.145515" y="245.273972" fill="green" font-size="12">48603</text>
<polyline points="237.444,532.384 232.67,485.309 172.758,486.599 177.778,534.575 237.444,532.384" fill="none" stroke="green" stroke-width="3" />
<text x="237.443558" y="532.384338" fill="green" font-size="12">48604</text>
<polyline points="216.631,347.064 212.562,302.017 154.301,297.594 158.851,344.357 216.631,347.064" fill="none" stroke="green" stroke-width="3" />
<text x="216.630951" y="347.064301" fill="green" font-size="12">48606</text>
<polyline points="337.795,439.96 330.585,395.771 277.674,394.691 282.245,439.68 337.795,439.96" fill="none" stroke="green" stroke-width="3" />
<text x="337.794800" y="439.960144" fill="green" font-size="12">48609</text>
<polyline points="315.488,266.903 311.849,224.639 259.014,217.852 263.363,262.02 315.488,266.903" fill="none" stroke="green" stroke-width="3" />
<text x="315.487518" y="266.903290" fill="green" font-size="12">48611</text>
<polyline points="444.487,522.683 439.544,480.798 390.689,481.531 395.723,524.38 444.487,522.683" fill="none" stroke="green" stroke-width="3" />
<text x="444.486633" y="522.683228" fill="green" font-size="12">48612</text>
<polyline points="424.254,357.528 418.145,316.254 370.656,312.942 375.639,354.946 424.254,357.528" fill="none" stroke="green" stroke-width="3" />
<text x="424.254028" y="357.527649" fill="green" font-size="12">48614</text>
<polyline points="524.131,440.143 518.483,400.44 474.786,399.468 479.742,439.829 524.131,440.143" fill="none" stroke="green" stroke-width="3" />
<text x="524.130798" y="440.142609" fill="green" font-size="12">48617</text>
<polyline points="503.282,284.007 498.349,245.13 454.578,240.281 459.621,279.853 503.282,284.007" fill="none" stroke="green" stroke-width="3" />
<text x="503.282379" y="284.006531" fill="green" font-size="12">48619</text>
<polyline points="113.413,536.891 108.2,486.684 41.2089,487.801 46.0645,539.5 113.413,536.891" fill="none" stroke="green" stroke-width="3" />
<text x="113.413376" y="536.890869" fill="green" font-size="12">48600</text>
<polyline points="161.438,390.917 165.37,439.293 226.656,439.598 220.325,392.921 161.438,390.917" fill="none" stroke="green" stroke-width="3" />
<text x="161.437576" y="390.916840" fill="green" font-size="12">48605</text>
<polyline points="207.906,256.612 204.111,210.875 143.436,203.321 148.534,250.846 207.906,256.612" fill="none" stroke="green" stroke-width="3" />
<text x="207.905884" y="256.611755" fill="green" font-size="12">48607</text>
<polyline points="344.03,528.151 338.21,483.178 283.31,483.638 288.533,530.062 344.03,528.151" fill="none" stroke="green" stroke-width="3" />
<text x="344.029724" y="528.150574" fill="green" font-size="12">48608</text>
<polyline points="325.236,353.673 320.333,310.113 267.727,306.292 271.578,350.06 325.236,353.673" fill="none" stroke="green" stroke-width="3" />
<text x="325.236298" y="353.672607" fill="green" font-size="12">48610</text>
<polyline points="379.694,397.919 383.775,440.47 433.692,441.264 428.466,399.601 379.694,397.919" fill="none" stroke="green" stroke-width="3" />
<text x="379.693573" y="397.918732" fill="green" font-size="12">48613</text>
<polyline points="414.263,276.515 410.385,236.083 362.791,231.432 366.332,272.093 414.263,276.515" fill="none" stroke="green" stroke-width="3" />
<text x="414.263428" y="276.515167" fill="green" font-size="12">48615</text>
<polyline points="532.209,521.014 527.509,481.012 482.64,481.267 487.556,522.566 532.209,521.014" fill="none" stroke="green" stroke-width="3" />
<text x="532.209351" y="521.014099" fill="green" font-size="12">48616</text>
<polyline points="513.143,363.443 506.917,323.424 463.47,320.164 468.795,360.542 513.143,363.443" fill="none" stroke="green" stroke-width="3" />
<text x="513.142700" y="363.443085" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.83027038725
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-12.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="449.389,528.154 414.49,532.364 415.015,578.261 449.636,574.586 449.389,528.154" fill="none" stroke="green" stroke-width="3" />
<text x="449.389191" y="528.153564" fill="green" font-size="12">48601</text>
<polyline points="318.298,545.141 285.711,548.773 287.065,591.858 318.288,588.834 318.298,545.141" fill="none" stroke="green" stroke-width="3" />
<text x="318.298492" y="545.140564" fill="green" font-size="12">48603</text>
<polyline points="519.482,422.83 481.858,429.777 483.058,476.621 519.695,471.04 519.482,422.83" fill="none" stroke="green" stroke-width="3" />
<text x="519.482239" y="422.830261" fill="green" font-size="12">48604</text>
<polyline points="381.949,447.838 349.403,453.597 349.204,497.17 381.573,492.473 381.949,447.838" fill="none" stroke="green" stroke-width="3" />
<text x="381.949127" y="447.837952" fill="green" font-size="12">48606</text>
<polyline points="445.61,345.667 411.475,352.892 412.795,397.474 446.471,390.547 445.61,345.667" fill="none" stroke="green" stroke-width="3" />
<text x="445.609863" y="345.667053" fill="green" font-size="12">48609</text>
<polyline points="316.837,373.322 289.007,380.853 288.867,422.391 316.957,416.265 316.837,373.322" fill="none" stroke="green" stroke-width="3" />
<text x="316.837280" y="373.322449" fill="green" font-size="12">48611</text>
<polyline points="513.637,237.215 477.862,246.604 479.161,291.914 514.729,282.953 513.637,237.215" fill="none" stroke="green" stroke-width="3" />
<text x="513.637085" y="237.214569" fill="green" font-size="12">48612</text>
<polyline points="379.272,273.819 347.61,282.036 347.336,323.899 379.685,316.917 379.272,273.819" fill="none" stroke="green" stroke-width="3" />
<text x="379.272125" y="273.819183" fill="green" font-size="12">48614</text>
<polyline points="445.219,168.574 411.057,178.722 411.071,222.259 444.655,212.678 445.219,168.574" fill="none" stroke="green" stroke-width="3" />
<text x="445.219391" y="168.574158" fill="green" font-size="12">48617</text>
<polyline points="319.947,208.123 291.098,217.633 290.435,258.082 318.112,249.028 319.947,208.123" fill="none" stroke="green" stroke-width="3" />
<text x="319.946808" y="208.123108" fill="green" font-size="12">48619</text>
<polyline points="520.16,516.529 482.062,521.703 482.69,569.466 521.101,565.677 520.16,516.529" fill="none" stroke="green" stroke-width="3" />
<text x="520.159790" y="516.529175" fill="green" font-size="12">48600</text>
<polyline points="378.363,535.925 345.495,539.721 345.66,584.986 378.31,580.68 378.363,535.925" fill="none" stroke="green" stroke-width="3" />
<text x="378.363037" y="535.925354" fill="green" font-size="12">48602</text>
<polyline points="411.418,485.898 447.39,480.926 447.015,433.877 411.215,440.614 411.418,485.898" fill="none" stroke="green" stroke-width="3" />
<text x="411.418060" y="485.897827" fill="green" font-size="12">48605</text>
<polyline points="315.152,456.268 284.45,461.874 283.119,504.58 315.379,500.74 315.152,456.268" fill="none" stroke="green" stroke-width="3" />
<text x="315.152313" y="456.267578" fill="green" font-size="12">48607</text>
<polyline points="515.25,326.969 479.144,336.377 479.984,382.217 516.885,374.439 515.25,326.969" fill="none" stroke="green" stroke-width="3" />
<text x="515.249817" y="326.969238" fill="green" font-size="12">48608</text>
<polyline points="378.053,358.908 345.932,365.576 346.316,409.457 378.004,402.934 378.053,358.908" fill="none" stroke="green" stroke-width="3" />
<text x="378.052521" y="358.907959" fill="green" font-size="12">48610</text>
<polyline points="409.84,307.328 444.107,299.49 443.746,254.414 409.587,263.626 409.84,307.328" fill="none" stroke="green" stroke-width="3" />
<text x="409.839600" y="307.328125" fill="green" font-size="12">48613</text>
<polyline points="513.789,145.979 477.289,157.132 477.219,201.516 513.863,191.889 513.789,145.979" fill="none" stroke="green" stroke-width="3" />
<text x="513.788574" y="145.978683" fill="green" font-size="12">48616</text>
<polyline points="379.252,187.789 346.92,197.151 346.528,238.513 378.183,230.733 379.252,187.789" fill="none" stroke="green" stroke-width="3" />
<text x="379.252136" y="187.789291" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.34260804628
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-13.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1052.53,157.188 1052.23,193.389 1095.32,193.191 1094.95,156.971 1052.53,157.188" fill="none" stroke="green" stroke-width="3" />
<text x="1052.528687" y="157.187790" fill="green" font-size="12">48601</text>
<polyline points="1052.21,305.428 1052.46,343.464 1096.25,343.87 1096.29,305.013 1052.21,305.428" fill="none" stroke="green" stroke-width="3" />
<text x="1052.206787" y="305.428101" fill="green" font-size="12">48603</text>
<polyline points="971.912,90.9223 970.733,125.06 1012.17,125.208 1012.15,89.8128 971.912,90.9223" fill="none" stroke="green" stroke-width="3" />
<text x="971.912415" y="90.922264" fill="green" font-size="12">48604</text>
<polyline points="967.488,230.942 966.609,267.274 1009.64,268.242 1010.37,231.057 967.488,230.942" fill="none" stroke="green" stroke-width="3" />
<text x="967.488159" y="230.941681" fill="green" font-size="12">48606</text>
<polyline points="887.061,157.464 885.002,193.691 927.278,194.286 928.883,157.873 887.061,157.464" fill="none" stroke="green" stroke-width="3" />
<text x="887.060913" y="157.463745" fill="green" font-size="12">48609</text>
<polyline points="878.816,303.766 877.17,343.88 920.487,344.197 922.152,303.888 878.816,303.766" fill="none" stroke="green" stroke-width="3" />
<text x="878.815857" y="303.766144" fill="green" font-size="12">48611</text>
<polyline points="810.125,86.6928 807.38,121.667 848.813,123.066 850.246,87.9601 810.125,86.6928" fill="none" stroke="green" stroke-width="3" />
<text x="810.125427" y="86.692841" fill="green" font-size="12">48612</text>
<polyline points="798.754,228.354 796.159,265.858 838.738,266.165 841.599,229.331 798.754,228.354" fill="none" stroke="green" stroke-width="3" />
<text x="798.753723" y="228.354401" fill="green" font-size="12">48614</text>
<polyline points="721.826,153.315 717.892,189.538 760.465,191.226 763.653,155.107 721.826,153.315" fill="none" stroke="green" stroke-width="3" />
<text x="721.825806" y="153.315475" fill="green" font-size="12">48617</text>
<polyline points="706.293,301.517 702.404,340.029 745.532,341.485 749.751,302.559 706.293,301.517" fill="none" stroke="green" stroke-width="3" />
<text x="706.293152" y="301.516876" fill="green" font-size="12">48619</text>
<polyline points="1053.5,88.3083 1053.45,123.143 1095.53,123.321 1094.5,87.8459 1053.5,88.3083" fill="none" stroke="green" stroke-width="3" />
<text x="1053.495850" y="88.308304" fill="green" font-size="12">48600</text>
<polyline points="1052.95,228.853 1053.2,266.806 1097.09,266.56 1096.56,228.912 1052.95,228.853" fill="none" stroke="green" stroke-width="3" />
<text x="1052.954712" y="228.852646" fill="green" font-size="12">48602</text>
<polyline points="970.637,157.803 969.213,195.071 1012.38,194.867 1013.17,157.97 970.637,157.803" fill="none" stroke="green" stroke-width="3" />
<text x="970.636841" y="157.802673" fill="green" font-size="12">48605</text>
<polyline points="966.161,303.23 965.944,343.331 1010.09,343.322 1010.21,303.838 966.161,303.23" fill="none" stroke="green" stroke-width="3" />
<text x="966.160828" y="303.230164" fill="green" font-size="12">48607</text>
<polyline points="891.915,88.7228 890.529,123.506 931.589,123.981 933.158,89.8362 891.915,88.7228" fill="none" stroke="green" stroke-width="3" />
<text x="891.915039" y="88.722786" fill="green" font-size="12">48608</text>
<polyline points="884.257,228.931 882.192,266.481 925.678,266.907 927.533,229.211 884.257,228.931" fill="none" stroke="green" stroke-width="3" />
<text x="884.256775" y="228.930695" fill="green" font-size="12">48610</text>
<polyline points="805.874,155.011 802.851,191.792 845.85,193.099 848.044,155.621 805.874,155.011" fill="none" stroke="green" stroke-width="3" />
<text x="805.874146" y="155.010681" fill="green" font-size="12">48613</text>
<polyline points="793.88,301.763 790.62,341.099 835.07,342.259 837.309,302.492 793.88,301.763" fill="none" stroke="green" stroke-width="3" />
<text x="793.880493" y="301.762512" fill="green" font-size="12">48615</text>
<polyline points="730.911,84.6644 727.124,119.45 768.819,120.577 771.829,85.5472 730.911,84.6644" fill="none" stroke="green" stroke-width="3" />
<text x="730.910706" y="84.664383" fill="green" font-size="12">48616</text>
<polyline points="715.602,225.177 711.426,262.848 755.006,263.613 758.854,226.392 715.602,225.177" fill="none" stroke="green" stroke-width="3" />
<text x="715.602051" y="225.177017" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 0.738898030151
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-14.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1553.72,133.092 1563.61,174.092 1613.6,157.766 1603.34,115.987 1553.72,133.092" fill="none" stroke="green" stroke-width="3" />
<text x="1553.724854" y="133.092209" fill="green" font-size="12">48601</text>
<polyline points="1593.31,295.632 1603.91,336.236 1654.12,323.394 1643.9,281.475 1593.31,295.632" fill="none" stroke="green" stroke-width="3" />
<text x="1593.311890" y="295.631622" fill="green" font-size="12">48603</text>
<polyline points="1445.19,90.0333 1453.12,128.696 1499.08,111.816 1489.56,72.2503 1445.19,90.0333" fill="none" stroke="green" stroke-width="3" />
<text x="1445.189575" y="90.033272" fill="green" font-size="12">48604</text>
<polyline points="1479.96,243.633 1489.17,282.961 1535.71,269.141 1526.81,228.814 1479.96,243.633" fill="none" stroke="green" stroke-width="3" />
<text x="1479.963989" y="243.632904" fill="green" font-size="12">48606</text>
<polyline points="1376.45,196.288 1384.53,234.247 1427.94,220.01 1419.45,181.131 1376.45,196.288" fill="none" stroke="green" stroke-width="3" />
<text x="1376.445190" y="196.288300" fill="green" font-size="12">48609</text>
<polyline points="1409.14,346.993 1417.65,385.809 1461.91,374.345 1452.72,334.926 1409.14,346.993" fill="none" stroke="green" stroke-width="3" />
<text x="1409.137939" y="346.993469" fill="green" font-size="12">48611</text>
<polyline points="1281.34,152.544 1288.94,189.175 1328.66,174.741 1320.71,137.811 1281.34,152.544" fill="none" stroke="green" stroke-width="3" />
<text x="1281.339722" y="152.543762" fill="green" font-size="12">48612</text>
<polyline points="1311.62,297.277 1319.5,333.456 1359.37,321.428 1351.73,284.654 1311.62,297.277" fill="none" stroke="green" stroke-width="3" />
<text x="1311.624146" y="297.276917" fill="green" font-size="12">48614</text>
<polyline points="1221.93,250.747 1228.88,285.993 1265.77,273.631 1258.83,237.938 1221.93,250.747" fill="none" stroke="green" stroke-width="3" />
<text x="1221.931274" y="250.747498" fill="green" font-size="12">48617</text>
<polyline points="1250.69,392.101 1257.74,428.166 1295.69,418.072 1288.29,381.367 1250.69,392.101" fill="none" stroke="green" stroke-width="3" />
<text x="1250.692993" y="392.101196" fill="green" font-size="12">48619</text>
<polyline points="1535.4,54.9133 1544.86,94.5622 1593.63,76.5964 1583.18,36.7477 1535.4,54.9133" fill="none" stroke="green" stroke-width="3" />
<text x="1535.401978" y="54.913307" fill="green" font-size="12">48600</text>
<polyline points="1572.68,213.413 1582.85,254.925 1633.83,239.938 1623.56,197.78 1572.68,213.413" fill="none" stroke="green" stroke-width="3" />
<text x="1572.679565" y="213.412918" fill="green" font-size="12">48602</text>
<polyline points="1469.94,206.516 1516.98,191.118 1507.94,150.146 1460.89,166.988 1469.94,206.516" fill="none" stroke="green" stroke-width="3" />
<text x="1469.938721" y="206.515533" fill="green" font-size="12">48605</text>
<polyline points="1498.98,321.366 1506.4,362.501 1555.1,348.82 1545.04,308.361 1498.98,321.366" fill="none" stroke="green" stroke-width="3" />
<text x="1498.980103" y="321.365814" fill="green" font-size="12">48607</text>
<polyline points="1359.45,122.671 1367.42,161.219 1410.52,145.492 1401.59,106.996 1359.45,122.671" fill="none" stroke="green" stroke-width="3" />
<text x="1359.451660" y="122.670517" fill="green" font-size="12">48608</text>
<polyline points="1391.82,272.122 1400.07,310.095 1443.51,297.098 1435.31,258.224 1391.82,272.122" fill="none" stroke="green" stroke-width="3" />
<text x="1391.823120" y="272.121887" fill="green" font-size="12">48610</text>
<polyline points="1303.32,261.778 1343.9,248.56 1336.25,210.368 1295.94,224.415 1303.32,261.778" fill="none" stroke="green" stroke-width="3" />
<text x="1303.319336" y="261.778351" fill="green" font-size="12">48613</text>
<polyline points="1326.47,370.716 1334.26,408.357 1375.25,397.868 1367.29,359.333 1326.47,370.716" fill="none" stroke="green" stroke-width="3" />
<text x="1326.474976" y="370.715607" fill="green" font-size="12">48615</text>
<polyline points="1207.62,180.704 1214.55,216.824 1252.01,203.147 1244.75,166.555 1207.62,180.704" fill="none" stroke="green" stroke-width="3" />
<text x="1207.622070" y="180.703964" fill="green" font-size="12">48616</text>
<polyline points="1236.03,321.214 1243.16,356.981 1280.84,346.027 1273.31,309.48 1236.03,321.214" fill="none" stroke="green" stroke-width="3" />
<text x="1236.033203" y="321.214142" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.62738649114
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-15.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1255.7,388.137 1251.02,445.53 1307.39,443.853 1312.76,386.928 1255.7,388.137" fill="none" stroke="green" stroke-width="3" />
<text x="1255.699829" y="388.136688" fill="green" font-size="12">48601</text>
<polyline points="1239.73,601.371 1236.68,651.07 1287.76,649.577 1292.41,600.228 1239.73,601.371" fill="none" stroke="green" stroke-width="3" />
<text x="1239.727051" y="601.371399" fill="green" font-size="12">48603</text>
<polyline points="1147.26,271.473 1145.18,332.074 1202.91,330.966 1206.82,270.446 1147.26,271.473" fill="none" stroke="green" stroke-width="3" />
<text x="1147.258789" y="271.473053" fill="green" font-size="12">48604</text>
<polyline points="1137.67,501.255 1135.62,553.909 1189.95,552.754 1193.53,499.673 1137.67,501.255" fill="none" stroke="green" stroke-width="3" />
<text x="1137.674683" y="501.254913" fill="green" font-size="12">48606</text>
<polyline points="1029.64,393.476 1029.01,450.736 1085.34,449.411 1086.36,392.575 1029.64,393.476" fill="none" stroke="green" stroke-width="3" />
<text x="1029.636353" y="393.476013" fill="green" font-size="12">48609</text>
<polyline points="1029.09,606.413 1028.92,654.209 1080.77,652.989 1082.07,605.387 1029.09,606.413" fill="none" stroke="green" stroke-width="3" />
<text x="1029.088501" y="606.413452" fill="green" font-size="12">48611</text>
<polyline points="911.075,276.23 913.477,337.422 971.42,335.891 970.828,275.242 911.075,276.23" fill="none" stroke="green" stroke-width="3" />
<text x="911.075012" y="276.230469" fill="green" font-size="12">48612</text>
<polyline points="919.15,506 921.341,559.042 976.094,557.775 975.237,504.786 919.15,506" fill="none" stroke="green" stroke-width="3" />
<text x="919.149841" y="505.999939" fill="green" font-size="12">48614</text>
<polyline points="800.865,398.154 804.965,455.395 862.443,455.207 858.716,397.235 800.865,398.154" fill="none" stroke="green" stroke-width="3" />
<text x="800.865417" y="398.153564" fill="green" font-size="12">48617</text>
<polyline points="817.13,611.343 820.856,659.969 873.256,658.937 870.209,610.112 817.13,611.343" fill="none" stroke="green" stroke-width="3" />
<text x="817.130249" y="611.342651" fill="green" font-size="12">48619</text>
<polyline points="1262.01,271.153 1257.41,331.515 1315.75,330.243 1321.73,269.976 1262.01,271.153" fill="none" stroke="green" stroke-width="3" />
<text x="1262.005249" y="271.153259" fill="green" font-size="12">48600</text>
<polyline points="1243.67,499.388 1239.41,552.76 1294.4,552.084 1299.76,498.953 1243.67,499.388" fill="none" stroke="green" stroke-width="3" />
<text x="1243.669922" y="499.388092" fill="green" font-size="12">48602</text>
<polyline points="1135.97,449.677 1193.04,449.324 1196.57,391.738 1139,392.404 1135.97,449.677" fill="none" stroke="green" stroke-width="3" />
<text x="1135.966187" y="449.677094" fill="green" font-size="12">48605</text>
<polyline points="1131.02,604.597 1127.74,654.367 1180.69,652.846 1184.05,603.718 1131.02,604.597" fill="none" stroke="green" stroke-width="3" />
<text x="1131.020508" y="604.596680" fill="green" font-size="12">48607</text>
<polyline points="1026.43,275.977 1026.09,337.427 1084.48,335.21 1086.13,275.842 1026.43,275.977" fill="none" stroke="green" stroke-width="3" />
<text x="1026.432983" y="275.976837" fill="green" font-size="12">48608</text>
<polyline points="1024.88,504.724 1024.79,557.832 1079.8,557.027 1081.06,503.469 1024.88,504.724" fill="none" stroke="green" stroke-width="3" />
<text x="1024.884399" y="504.723969" fill="green" font-size="12">48610</text>
<polyline points="913.945,453.659 971.481,453.367 970.403,394.959 912.237,395.764 913.945,453.659" fill="none" stroke="green" stroke-width="3" />
<text x="913.944580" y="453.659027" fill="green" font-size="12">48613</text>
<polyline points="919.647,609.295 920.405,659.233 972.941,657.444 972.74,608.38 919.647,609.295" fill="none" stroke="green" stroke-width="3" />
<text x="919.646973" y="609.295410" fill="green" font-size="12">48615</text>
<polyline points="789.46,276.95 793.62,339.281 853.132,339.043 849.148,276.958 789.46,276.95" fill="none" stroke="green" stroke-width="3" />
<text x="789.459595" y="276.949677" fill="green" font-size="12">48616</text>
<polyline points="806.015,508.322 809.568,561.605 864.443,561.062 862.566,507.445 806.015,508.322" fill="none" stroke="green" stroke-width="3" />
<text x="806.015076" y="508.322021" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
</ol>
} pose {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg} height 1080 coords {806.015,508.322 809.568,561.605 864.443,561.062 862.566,507.445 806.015,508.322}}}
when the collected results for {/any/ wishes folk-sva uses display glfw with /...any/} are /__results (
[ m1097:0 (s1892:0) ]
[ m1099:0 (s3341:0 s3342:0 s3343:0) ]
)when the collected results for {/any/ wishes folk-sva uses display glfw with /...any/} are /__results/ {if {[llength $__results] == 0} {
gpuInit false
}} with environment {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} ^gpuInit {useGlfw {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
} {builtin-programs/gpu/gpu.folk 34}}} {} {}}
when the collected results for {the changer from space /sourceSpace/ to space /targetSpace/ is /chang (
[ m1400:0 (s2264:0) ]
[ m1404:0 (s2268:0) ]
)when the collected results for {the changer from space /sourceSpace/ to space /targetSpace/ is /changer/} are /results/ \n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the collected results for {/any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:0 (
[ m4495:0 (s6295:0) ]
[ m4499:0 () ]
)when the collected results for {/any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is /anything/} are /__results/ {if {[llength $__results] == 0} {When the calibration refiner is /refineCalibration/ \n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n}} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det ^setCameraToProjectorExtrinsics {{modelLib calibrationVar calibrationPoses} \n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n {builtin-programs/calibrate/calibrate.folk 543}} ^unrefinedCalibrateCameraAndProjector {{modelLib matLib calibrationPoses} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/calibrate.folk 613}} ^processHomography {H \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n {builtin-programs/calibrate/calibrate.folk 413}} ^zhangUnrefinedCalibrate {{name width height Hs} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n {builtin-programs/calibrate/calibrate.folk 452}}} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {} {calibrationPosesMax 10} {} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 display monitor calibrationPoses {{model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 28 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-75314.698413 4478.401730 19997.029253 }{-971.492484 -71792.210770 22876.355728 }{-1.407849 2.419020 18.216270 }} rmse 0.725728225238 tags {48601 {id 48601 c {1385.029589 373.397601} p {{1367.431885 391.921936} {1405.210205 389.762604} {1402.768921 354.724182} {1364.972778 357.132996}} size 37 angle 0.057096} 48603 {id 48603 c {1538.393435 364.163451} p {{1520.251709 382.996368} {1560.268555 380.483032} {1556.391846 345.479309} {1516.824951 348.072632}} size 40 angle 0.062725} 48604 {id 48604 c {1314.707595 447.429039} p {{1296.983887 465.832520} {1334.821533 464.710083} {1332.746704 428.698059} {1294.883911 430.397369}} size 37 angle 0.029656} 48606 {id 48606 c {1466.610059 439.916687} p {{1448.426758 459.265656} {1487.840576 457.079193} {1484.453857 420.928986} {1445.619263 422.947968}} size 39 angle 0.055418} 48609 {id 48609 c {1394.987112 514.999554} p {{1377.006226 533.712585} {1415.902588 532.740601} {1413.313599 495.926849} {1374.507446 497.628174}} size 38 angle 0.024984} 48611 {id 48611 c {1551.315859 508.245212} p {{1533.442505 527.498169} {1572.451660 526.567932} {1569.045044 489.147552} {1530.549683 490.242920}} size 39 angle 0.023842} 48612 {id 48612 c {1323.958123 589.924482} p {{1306.240601 608.614990} {1344.435791 607.666931} {1341.827026 571.074280} {1303.762695 572.426575}} size 38 angle 0.024816} 48614 {id 48614 c {1479.024930 584.982536} p {{1460.857666 603.967041} {1500.821045 602.853821} {1497.578369 565.594482} {1457.400269 567.251831}} size 39 angle 0.027849} 48617 {id 48617 c {1406.285006 661.290040} p {{1388.146118 680.364746} {1427.638062 679.629700} {1424.388550 642.252502} {1385.154663 643.141663}} size 39 angle 0.018610} 48619 {id 48619 c {1565.543612 657.303678} p {{1547.084473 676.826904} {1587.975098 675.831177} {1583.959351 637.826355} {1543.498535 639.095337}} size 40 angle 0.024346} 48600 {id 48600 c {1311.069046 378.239945} p {{1293.403809 397.174408} {1331.194946 394.612976} {1328.710938 359.330505} {1291.372437 362.216156}} size 37 angle 0.067675} 48602 {id 48602 c {1460.901364 369.680924} p {{1443.130371 388.178741} {1482.119629 386.910889} {1479.017700 350.823639} {1440.809570 353.365692}} size 39 angle 0.032507} 48605 {id 48605 c {1390.772515 444.293298} p {{1372.398560 463.838928} {1411.644775 461.251099} {1408.589966 425.339661} {1369.880737 427.319641}} size 39 angle 0.065843} 48607 {id 48607 c {1544.826101 436.656867} p {{1526.837891 455.811432} {1566.585449 454.317230} {1563.773438 416.480988} {1523.533813 419.375580}} size 39 angle 0.037575} 48608 {id 48608 c {1320.136780 518.359033} p {{1302.109009 537.349243} {1340.637085 535.987244} {1338.151733 499.382324} {1299.486084 500.601501}} size 38 angle 0.035336} 48610 {id 48610 c {1472.920554 512.574182} p {{1454.544067 531.717834} {1494.853027 530.374573} {1491.634033 493.079468} {1451.511475 495.198578}} size 40 angle 0.033312} 48613 {id 48613 c {1401.442760 587.735040} p {{1383.686401 606.712585} {1422.481323 605.905945} {1419.349243 568.597046} {1380.474243 569.624634}} size 38 angle 0.020789} 48615 {id 48615 c {1558.880689 582.530694} p {{1540.743286 601.986816} {1580.547241 600.764343} {1576.885620 563.216675} {1537.027832 564.140259}} size 39 angle 0.030703} 48616 {id 48616 c {1329.655113 663.051861} p {{1311.354126 682.407532} {1350.495972 681.459778} {1347.780396 643.882019} {1309.224487 645.006287}} size 39 angle 0.024209} 48618 {id 48618 c {1486.141093 659.716024} p {{1467.177856 679.632935} {1507.811157 677.993408} {1504.760864 640.159851} {1464.393188 641.372986}} size 40 angle 0.040327}} imageName pose-1781543257841-0.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 43 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1056840.114219 42808.811083 264863.141447 }{32312.866960 -1007364.955709 402770.605979 }{-11.182218 42.695320 245.704300 }} rmse 1.89131853376 tags {48601 {id 48601 c {1395.952641 212.861420} p {{1377.588257 233.639587} {1417.538696 229.658676} {1414.197876 192.218063} {1374.617188 196.259171}} size 40 angle 0.099318} 48603 {id 48603 c {1553.635336 197.600660} p {{1535.305908 218.149307} {1575.980347 214.534927} {1571.934326 177.086136} {1531.557007 180.868500}} size 40 angle 0.088628} 48604 {id 48604 c {1324.137968 293.707576} p {{1306.116943 313.840912} {1345.083008 310.326050} {1341.587646 274.212555} {1303.338867 277.204895}} size 39 angle 0.089960} 48606 {id 48606 c {1480.843873 279.367657} p {{1462.405518 299.948456} {1502.627686 296.394623} {1499.185791 258.894501} {1459.289917 262.520355}} size 40 angle 0.088126} 48609 {id 48609 c {1408.072088 360.901788} p {{1390.102661 380.931671} {1429.527344 377.933807} {1426.243774 340.646454} {1386.851929 344.056396}} size 39 angle 0.075894} 48611 {id 48611 c {1567.259040 347.361196} p {{1549.179443 367.838379} {1588.584595 365.235809} {1584.650513 327.663391} {1546.489990 329.953033}} size 39 angle 0.065951} 48612 {id 48612 c {1336.656619 441.631250} p {{1318.508179 462.043243} {1358.458130 459.201569} {1354.721069 421.313721} {1315.223755 424.358032}} size 40 angle 0.071011} 48614 {id 48614 c {1494.646192 429.683558} p {{1476.802612 449.946777} {1516.712524 447.297180} {1512.817993 409.047607} {1472.774170 412.225037}} size 39 angle 0.066292} 48617 {id 48617 c {1423.249643 510.798629} p {{1404.714844 531.413879} {1445.430786 528.574585} {1441.903687 490.050751} {1400.936401 492.916809}} size 40 angle 0.069622} 48619 {id 48619 c {1583.746862 499.650259} p {{1566.048706 520.226074} {1606.481323 517.599731} {1601.709229 478.767273} {1560.927002 481.633362}} size 40 angle 0.064865} 48600 {id 48600 c {1318.372902 222.551387} p {{1299.982056 243.184250} {1339.737549 239.225800} {1336.857300 201.813568} {1296.936279 205.820801}} size 39 angle 0.099243} 48602 {id 48602 c {1474.613028 207.413025} p {{1456.190552 227.932159} {1496.754761 224.579254} {1493.370117 186.521194} {1452.811646 190.510666}} size 40 angle 0.082469} 48605 {id 48605 c {1402.289206 288.773703} p {{1381.081299 272.196045} {1383.976074 309.481049} {1423.905273 305.670410} {1420.299072 268.409271}} size 37 angle -1.493313} 48607 {id 48607 c {1560.824988 274.287257} p {{1542.879883 294.537292} {1582.193848 292.009033} {1578.751343 254.058380} {1539.623535 256.704315}} size 39 angle 0.064221} 48608 {id 48608 c {1330.693159 369.828011} p {{1312.406006 390.445038} {1352.469727 386.978882} {1349.092041 349.085022} {1309.401855 353.059326}} size 40 angle 0.086301} 48610 {id 48610 c {1488.474183 356.547666} p {{1469.599854 377.690796} {1510.819702 373.957123} {1506.693237 336.138580} {1466.973022 339.796051}} size 41 angle 0.090333} 48613 {id 48613 c {1416.229342 437.995789} p {{1394.115112 420.463196} {1397.874268 459.000122} {1438.656128 455.776184} {1434.263916 417.358215}} size 38 angle -1.473557} 48615 {id 48615 c {1575.955360 426.006059} p {{1557.106689 447.186432} {1598.870117 444.503754} {1594.429932 405.246063} {1553.894043 408.197296}} size 41 angle 0.064147} 48616 {id 48616 c {1344.023531 519.212660} p {{1325.910889 539.723450} {1366.120361 537.195007} {1362.370117 498.436951} {1322.228394 501.475830}} size 40 angle 0.062799} 48618 {id 48618 c {1504.497483 507.714315} p {{1485.648682 528.901550} {1527.599365 526.065979} {1523.404175 486.462006} {1481.829468 489.707306}} size 42 angle 0.067490}} imageName pose-1781543257841-1.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 64 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-209693.666866 32261.725933 45616.235897 }{9716.750647 -182727.705443 69957.706876 }{1.369661 20.418735 41.956332 }} rmse 1.12427806234 tags {48601 {id 48601 c {1509.711328 54.434227} p {{1480.648926 85.984230} {1536.133667 82.819717} {1538.859497 22.791117} {1483.493286 26.268213}} size 55 angle 0.056972} 48604 {id 48604 c {1394.354083 178.405525} p {{1365.312988 209.825806} {1421.084839 206.090240} {1423.003174 147.409363} {1367.770142 150.872864}} size 55 angle 0.066880} 48606 {id 48606 c {1610.914251 165.377982} p {{1581.291260 195.974930} {1636.133911 193.269714} {1640.511963 134.807144} {1585.921265 137.736938}} size 54 angle 0.049287} 48609 {id 48609 c {1495.829713 283.255061} p {{1467.725464 311.925690} {1520.545898 308.731995} {1524.365112 254.144592} {1470.828369 257.484192}} size 52 angle 0.060390} 48611 {id 48611 c {1706.065596 270.965025} p {{1678.112183 299.655853} {1728.069824 296.962830} {1733.845215 242.452576} {1684.113159 245.028412}} size 50 angle 0.053854} 48612 {id 48612 c {1385.763556 396.781625} p {{1358.841064 424.564758} {1411.064087 421.179443} {1412.717529 368.966003} {1360.271606 372.199219}} size 52 angle 0.064734} 48614 {id 48614 c {1592.767882 384.014632} p {{1565.013916 411.650513} {1615.941650 408.255951} {1620.917480 355.984802} {1568.793213 358.935516}} size 51 angle 0.066556} 48617 {id 48617 c {1484.082987 492.101955} p {{1456.933105 518.884766} {1508.521606 515.551514} {1511.408203 465.146179} {1459.290771 468.313110}} size 51 angle 0.064523} 48619 {id 48619 c {1684.106845 479.581249} p {{1656.806152 506.011230} {1707.054565 503.155701} {1711.697510 452.870544} {1661.051270 455.895996}} size 50 angle 0.056767} 48600 {id 48600 c {1399.789822 59.409994} p {{1369.518433 92.648804} {1426.722534 87.997520} {1428.329834 28.072285} {1372.388428 30.324989}} size 57 angle 0.081132} 48602 {id 48602 c {1620.425256 46.876868} p {{1590.636230 78.148476} {1645.181152 75.500832} {1650.330200 15.483572} {1595.297729 17.823208}} size 54 angle 0.048503} 48605 {id 48605 c {1502.972095 171.263498} p {{1473.294922 202.666061} {1529.038208 199.092056} {1532.439453 140.082947} {1476.357422 142.849289}} size 55 angle 0.064028} 48607 {id 48607 c {1716.798563 158.749720} p {{1687.903442 188.728394} {1740.135620 186.814194} {1747.215942 127.191704} {1692.823486 129.917984}} size 52 angle 0.036632} 48608 {id 48608 c {1389.683476 289.345012} p {{1361.929688 318.369263} {1415.511719 314.445282} {1418.558594 259.148102} {1363.436646 263.837952}} size 53 angle 0.073103} 48610 {id 48610 c {1601.362012 276.392144} p {{1572.501587 305.586060} {1625.155640 301.927612} {1630.324951 247.094528} {1577.106812 250.361313}} size 52 angle 0.069369} 48613 {id 48613 c {1489.824889 389.421889} p {{1462.307617 417.067352} {1514.499268 414.530518} {1517.472290 361.645691} {1465.068970 364.230286}} size 52 angle 0.048568} 48615 {id 48615 c {1694.785648 376.578606} p {{1666.799194 404.401581} {1716.849487 401.537170} {1721.927124 349.595673} {1672.444946 351.306854}} size 50 angle 0.057168} 48616 {id 48616 c {1381.972820 497.565982} p {{1355.683105 523.804565} {1407.246094 521.063721} {1409.440552 470.151672} {1356.126343 473.535309}} size 51 angle 0.053105} 48618 {id 48618 c {1585.154532 484.068682} p {{1557.027588 511.571320} {1609.122559 507.884888} {1612.781616 457.054810} {1561.358398 460.423279}} size 52 angle 0.070646}} imageName pose-1781543257841-2.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 84 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{98796.033601 -6946652.610637 2196614.745495 }{6739896.207720 460527.950943 1149462.297906 }{-190.312892 -80.550321 1480.650980 }} rmse 1.96923416025 tags {48601 {id 48601 c {1194.241663 327.654893} p {{1222.111084 348.784912} {1216.369019 300.245178} {1166.462280 306.593140} {1172.062500 355.128784}} size 48 angle 1.688545} 48603 {id 48603 c {1171.725758 137.153038} p {{1199.847046 158.204208} {1193.673950 110.035004} {1143.998901 116.397133} {1149.260986 164.909332}} size 48 angle 1.698256} 48604 {id 48604 c {1308.752097 412.254488} p {{1338.622192 434.530487} {1331.861450 384.154022} {1279.358032 390.333496} {1285.766602 440.204346}} size 50 angle 1.704204} 48606 {id 48606 c {1282.569227 218.915396} p {{1311.468262 240.157288} {1305.318115 190.902405} {1253.950073 197.879227} {1260.240479 246.411026}} size 49 angle 1.695017} 48609 {id 48609 c {1397.995160 301.536987} p {{1428.077271 322.549194} {1420.253662 274.268646} {1368.598511 281.003571} {1375.678467 328.876617}} size 48 angle 1.731445} 48611 {id 48611 c {1370.183598 111.469475} p {{1399.739502 131.376297} {1391.639771 85.337204} {1341.105835 91.884697} {1348.329224 138.086731}} size 46 angle 1.744946} 48612 {id 48612 c {1519.304013 386.697516} p {{1550.766846 409.180939} {1541.709717 358.774933} {1489.093506 365.109009} {1495.861572 415.912109}} size 51 angle 1.748583} 48614 {id 48614 c {1486.619487 192.485437} p {{1517.266602 213.760712} {1508.706177 165.099457} {1456.419800 171.520767} {1463.944824 220.600464}} size 49 angle 1.744933} 48617 {id 48617 c {1607.958935 275.600540} p {{1639.266846 297.007874} {1629.765137 248.022018} {1577.122803 254.515793} {1586.114258 303.227722}} size 49 angle 1.762386} 48619 {id 48619 c {1571.899693 85.866461} p {{1602.301147 106.652153} {1592.920166 59.605083} {1542.627441 65.852814} {1550.401001 112.725288}} size 47 angle 1.767611} 48600 {id 48600 c {1206.794202 426.590988} p {{1236.492432 449.318146} {1229.803345 398.072601} {1177.802734 404.404694} {1183.689575 455.227722}} size 51 angle 1.700593} 48602 {id 48602 c {1184.021152 232.821101} p {{1212.459473 253.815598} {1207.137085 204.863739} {1155.541260 211.795914} {1161.424805 260.150055}} size 49 angle 1.679098} 48605 {id 48605 c {1296.399419 316.668400} p {{1325.864990 337.833160} {1318.705078 289.045715} {1267.292847 295.761505} {1274.157593 344.212036}} size 49 angle 1.716513} 48607 {id 48607 c {1272.569361 125.751695} p {{1301.373169 146.699203} {1294.984741 99.184029} {1244.206299 105.124718} {1249.886353 152.636566}} size 47 angle 1.704445} 48608 {id 48608 c {1414.667729 402.124332} p {{1445.368042 424.986145} {1437.862793 373.319275} {1384.357422 379.552948} {1391.050537 431.453613}} size 52 angle 1.715050} 48610 {id 48610 c {1385.344625 207.908486} p {{1415.355225 229.484650} {1408.298096 180.034698} {1355.682983 186.583206} {1362.748413 235.348434}} size 49 angle 1.712552} 48613 {id 48613 c {1504.010825 290.592138} p {{1535.192505 311.400970} {1525.939331 263.201904} {1472.870605 269.810974} {1482.175293 317.866241}} size 49 angle 1.760467} 48615 {id 48615 c {1472.653357 100.909178} p {{1503.442139 121.380783} {1494.246338 74.729080} {1443.124634 81.275391} {1450.703613 127.521828}} size 47 angle 1.765417} 48616 {id 48616 c {1627.703024 377.014268} p {{1659.892212 399.384186} {1649.839233 348.795959} {1595.999512 354.981873} {1604.796143 406.214996}} size 51 angle 1.766962} 48618 {id 48618 c {1590.935498 182.266953} p {{1622.018433 204.144791} {1613.073486 154.467285} {1560.334961 160.728653} {1568.566406 210.356827}} size 50 angle 1.748948}} imageName pose-1781543257841-3.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 99 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-164.252607 -820.689643 321.050974 }{657.240586 2.194841 74.671280 }{-0.091003 -0.007578 0.199975 }} rmse 1.60197092768 tags {48601 {id 48601 c {1141.550955 582.403096} p {{1161.815552 600.761658} {1163.238403 562.024231} {1120.927490 563.719421} {1120.484253 602.198669}} size 38 angle 1.534082} 48603 {id 48603 c {1145.788283 418.406845} p {{1167.404541 439.410339} {1168.944092 395.168213} {1123.939575 397.177490} {1122.794189 441.483185}} size 44 angle 1.536012} 48604 {id 48604 c {1221.678530 654.892956} p {{1241.052490 672.530945} {1243.321289 635.811279} {1201.962158 636.943237} {1200.216064 673.815674}} size 36 angle 1.509088} 48606 {id 48606 c {1229.823309 499.788624} p {{1250.237061 519.468994} {1253.126953 477.784363} {1208.700195 479.424377} {1206.813232 521.515686}} size 41 angle 1.501580} 48609 {id 48609 c {1309.572061 576.229695} p {{1329.272949 595.172302} {1332.628296 555.744568} {1289.946289 557.359314} {1286.864502 596.405029}} size 39 angle 1.485900} 48611 {id 48611 c {1324.503629 410.281911} p {{1345.424316 431.919800} {1348.665894 386.653442} {1303.432983 388.488922} {1300.430908 433.822815}} size 45 angle 1.499307} 48612 {id 48612 c {1386.199225 649.691146} p {{1405.200684 668.071045} {1409.600952 630.438660} {1367.856934 631.948853} {1363.365601 668.476257}} size 37 angle 1.454397} 48614 {id 48614 c {1404.546747 492.311979} p {{1424.596436 512.734863} {1429.509399 470.110352} {1384.809814 472.207672} {1379.893799 514.238159}} size 42 angle 1.456041} 48617 {id 48617 c {1481.319865 570.522647} p {{1500.176636 589.614075} {1506.079590 549.730896} {1462.400513 551.367859} {1457.022339 590.926270}} size 40 angle 1.423857} 48619 {id 48619 c {1505.624037 402.192051} p {{1525.058838 423.735840} {1531.934570 378.371429} {1485.980469 380.416840} {1479.559814 425.789673}} size 45 angle 1.420375} 48600 {id 48600 c {1138.113454 658.341403} p {{1157.728149 676.412109} {1159.237061 639.123474} {1118.033081 639.841675} {1117.274170 677.300659}} size 37 angle 1.530353} 48602 {id 48602 c {1141.823652 502.541629} p {{1163.265625 522.951355} {1164.351807 480.563751} {1119.985718 481.755005} {1119.635254 524.188049}} size 42 angle 1.545177} 48605 {id 48605 c {1223.377045 580.184804} p {{1201.270752 599.937561} {1243.418579 599.076233} {1245.842407 560.111206} {1203.125610 561.095520}} size 42 angle 0.020433} 48607 {id 48607 c {1232.657392 413.568093} p {{1254.376343 435.440247} {1256.473877 390.930359} {1211.246704 392.006378} {1208.927002 436.123993}} size 44 angle 1.523706} 48608 {id 48608 c {1301.878842 653.889951} p {{1320.725586 671.876770} {1324.375000 634.329895} {1282.553223 635.446106} {1278.991821 673.789856}} size 37 angle 1.473904} 48610 {id 48610 c {1314.763363 497.048578} p {{1335.116821 517.577820} {1339.197754 475.334717} {1294.032349 476.138519} {1290.772095 518.368652}} size 42 angle 1.474489} 48613 {id 48613 c {1393.748209 574.806004} p {{1369.902954 595.453003} {1413.156860 593.946838} {1417.280640 554.429871} {1373.905273 555.236877}} size 43 angle 0.034807} 48615 {id 48615 c {1412.617496 407.403562} p {{1433.579224 429.078918} {1438.576172 383.783478} {1391.769043 385.845337} {1387.735352 430.044098}} size 45 angle 1.460922} 48616 {id 48616 c {1468.586555 649.108080} p {{1487.397583 667.221069} {1492.819580 629.765076} {1450.277710 631.478638} {1444.668457 668.199707}} size 37 angle 1.427038} 48618 {id 48618 c {1491.469528 490.510814} p {{1510.942993 511.321289} {1517.885132 468.175201} {1472.139771 469.853912} {1465.745728 512.261475}} size 43 angle 1.411265}} imageName pose-1781543257841-4.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 113 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-652.045996 -21.596042 316.832491 }{38.585632 -605.150208 263.674429 }{-0.025238 0.018629 0.147826 }} rmse 2.01227215325 tags {48601 {id 48601 c {977.930902 159.133678} p {{961.526062 180.890030} {998.662842 173.187088} {994.492188 137.169846} {957.513733 145.293640}} size 37 angle 0.204521} 48603 {id 48603 c {1128.442555 127.285638} p {{1111.380981 149.230835} {1150.937012 141.910492} {1145.978394 104.730423} {1106.935059 113.302460}} size 40 angle 0.182992} 48604 {id 48604 c {913.613811 244.410072} p {{897.504028 265.617676} {933.629150 258.775940} {929.834473 223.056503} {893.546875 230.007172}} size 36 angle 0.187173} 48606 {id 48606 c {1061.222644 215.459666} p {{1044.215210 237.679565} {1082.993774 230.328522} {1078.232056 193.237183} {1039.661499 200.734222}} size 39 angle 0.187342} 48609 {id 48609 c {994.600018 302.540949} p {{978.372559 323.581116} {1015.690918 317.462067} {1011.314331 280.869537} {973.992737 287.961975}} size 37 angle 0.162523} 48611 {id 48611 c {1148.040286 274.979104} p {{1130.848511 296.855865} {1170.356934 290.619507} {1165.280518 253.040680} {1125.903931 259.465057}} size 39 angle 0.156557} 48612 {id 48612 c {929.044403 388.400978} p {{912.621643 409.819275} {949.752258 403.972961} {945.610474 366.795776} {909.082642 373.390045}} size 37 angle 0.156171} 48614 {id 48614 c {1079.629903 363.319986} p {{1062.534424 385.340088} {1101.736694 378.890747} {1096.727173 341.297577} {1058.058228 348.126129}} size 39 angle 0.163054} 48617 {id 48617 c {1011.995130 450.385611} p {{994.765564 472.561249} {1033.851685 466.870331} {1029.125000 428.338287} {990.725464 434.343536}} size 39 angle 0.144583} 48619 {id 48619 c {1168.522487 426.853393} p {{1150.667725 449.554413} {1191.837036 443.555511} {1186.205078 404.371277} {1145.656982 410.472961}} size 41 angle 0.144695} 48600 {id 48600 c {906.411835 177.815006} p {{889.984741 199.787430} {926.487671 191.674118} {922.554993 156.222366} {886.374207 163.982269}} size 37 angle 0.218709} 48602 {id 48602 c {1051.843604 146.397340} p {{1034.971924 168.697723} {1073.739624 160.711548} {1068.651978 124.180634} {1030.366455 132.356964}} size 39 angle 0.203159} 48605 {id 48605 c {986.661165 233.698148} p {{1007.705933 248.093491} {1003.319397 211.708145} {965.541809 219.251785} {970.112244 255.543854}} size 36 angle 1.690775} 48607 {id 48607 c {1137.807079 202.742391} p {{1120.361816 225.086212} {1160.317017 218.317123} {1155.167358 180.507416} {1115.311768 187.177780}} size 40 angle 0.167823} 48608 {id 48608 c {922.560991 318.546825} p {{906.624146 340.189362} {942.870178 333.020996} {938.391785 297.048309} {902.168701 304.013428}} size 36 angle 0.195250} 48610 {id 48610 c {1070.498044 291.328487} p {{1053.658569 313.241547} {1092.294434 306.299133} {1087.534180 269.159515} {1048.903076 276.496185}} size 39 angle 0.177791} 48613 {id 48613 c {1004.548424 378.170736} p {{1026.171143 393.921082} {1021.375305 356.460602} {983.372803 362.746063} {987.668945 399.948730}} size 37 angle 1.698128} 48615 {id 48615 c {1158.497567 351.624066} p {{1141.118408 373.867371} {1181.446045 367.684326} {1175.558594 329.787933} {1136.038452 335.906281}} size 40 angle 0.152136} 48616 {id 48616 c {939.220193 463.734392} p {{922.379578 485.613617} {960.984741 480.247101} {955.976013 441.965332} {918.181152 447.772125}} size 38 angle 0.138125} 48618 {id 48618 c {1090.522811 440.062316} p {{1073.001709 463.023590} {1113.502075 456.692810} {1107.943359 417.232819} {1068.055298 423.802185}} size 40 angle 0.155059}} imageName pose-1781543257841-5.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 127 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-61350.964391 13718.747912 28186.840504 }{4013.252826 -47158.607425 24253.415873 }{0.442939 7.990373 13.206176 }} rmse 2.0423236365 tags {48601 {id 48601 c {995.655720 63.369710} p {{973.477661 90.745377} {1019.583435 88.357903} {1018.224365 35.511921} {971.392822 38.031479}} size 46 angle 0.051736} 48603 {id 48603 c {1180.455537 53.052164} p {{1156.181641 80.391281} {1202.452759 77.794220} {1204.506226 25.964441} {1158.137085 27.948795}} size 46 angle 0.056068} 48604 {id 48604 c {910.089626 169.639338} p {{889.396729 195.435806} {934.235474 192.824677} {931.088196 143.461807} {885.473083 146.002029}} size 44 angle 0.058168} 48606 {id 48606 c {1087.511228 159.278386} p {{1065.120605 184.974594} {1109.740112 182.464233} {1110.227051 133.208969} {1065.099487 135.901810}} size 44 angle 0.056202} 48609 {id 48609 c {1001.921881 257.661450} p {{981.454956 281.020996} {1023.606201 278.443939} {1022.982117 233.624741} {979.547729 236.217819}} size 42 angle 0.061062} 48611 {id 48611 c {1172.079885 247.141943} p {{1150.322266 270.640564} {1191.790283 267.688171} {1194.587402 222.833420} {1151.829712 226.033051}} size 41 angle 0.071077} 48612 {id 48612 c {922.703804 348.671427} p {{903.591309 370.806976} {944.802917 368.033569} {941.781982 326.575623} {900.360535 329.095367}} size 41 angle 0.067195} 48614 {id 48614 c {1086.742713 338.234140} p {{1066.020996 360.519623} {1107.078979 357.741791} {1107.172485 316.262634} {1066.420776 318.740234}} size 41 angle 0.067553} 48617 {id 48617 c {1007.363271 423.517549} p {{987.993103 444.138885} {1027.957153 441.846527} {1026.905151 402.713409} {987.214966 405.585144}} size 40 angle 0.057298} 48619 {id 48619 c {1165.054318 412.989596} p {{1144.602783 433.873840} {1183.831665 430.969727} {1185.664429 391.943420} {1146.122681 394.861725}} size 39 angle 0.073895} 48600 {id 48600 c {901.093923 70.459400} p {{879.565063 98.831100} {926.215210 95.174049} {922.728394 41.948521} {875.173706 44.958752}} size 46 angle 0.078233} 48602 {id 48602 c {1085.779535 59.660986} p {{1062.445923 87.665062} {1108.789673 85.055267} {1109.044922 31.738792} {1062.930176 34.444141}} size 46 angle 0.056254} 48605 {id 48605 c {997.285938 166.825402} p {{973.270996 143.105530} {975.749329 192.658005} {1021.540161 190.781616} {1018.919434 140.876587}} size 49 angle -1.520824} 48607 {id 48607 c {1173.617485 154.937350} p {{1150.805542 180.724335} {1195.427490 177.985092} {1197.802246 127.598511} {1151.804687 131.886658}} size 44 angle 0.061311} 48608 {id 48608 c {915.100492 265.275558} p {{895.314270 289.225830} {938.357666 286.459778} {935.249207 240.886505} {891.717712 243.976929}} size 43 angle 0.064174} 48610 {id 48610 c {1085.493242 255.170662} p {{1064.236572 278.830505} {1106.522827 275.830505} {1107.605225 230.558807} {1063.488892 233.553192}} size 42 angle 0.070826} 48613 {id 48613 c {1003.760979 346.516282} p {{982.015869 326.394714} {984.393250 368.502594} {1025.032593 366.199707} {1023.765808 323.806732}} size 42 angle -1.514397} 48615 {id 48615 c {1167.279457 334.932959} p {{1146.137329 356.945221} {1186.635132 354.646179} {1188.529785 312.808044} {1147.281250 314.565338}} size 40 angle 0.056709} 48616 {id 48616 c {927.208690 432.071257} p {{908.725525 452.526123} {949.156921 450.607025} {946.694458 410.506836} {905.706055 413.911804}} size 40 angle 0.047430} 48618 {id 48618 c {1085.678921 420.576598} p {{1065.630981 441.996979} {1105.944946 439.000702} {1105.520752 399.376434} {1065.620117 402.340881}} size 40 angle 0.074187}} imageName pose-1781543257841-6.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 139 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1293234.230097 -236546.444378 661933.879650 }{123504.689570 -1164505.518365 389497.399567 }{-24.466768 -74.390643 296.571025 }} rmse 1.41663092406 tags {48601 {id 48601 c {949.478206 319.501544} p {{930.948975 336.128265} {970.724487 329.256683} {967.531921 303.301514} {928.905212 310.055542}} size 40 angle 0.171071} 48603 {id 48603 c {1108.382342 293.125748} p {{1091.457397 309.351135} {1132.334351 302.969696} {1125.304199 276.903320} {1085.332153 283.652435}} size 41 angle 0.154863} 48604 {id 48604 c {873.740912 387.403626} p {{853.658752 405.510284} {894.607117 398.498199} {893.467712 369.617371} {852.656311 376.192932}} size 41 angle 0.169597} 48606 {id 48606 c {1038.223024 362.779168} p {{1020.033813 380.388397} {1062.753662 374.629364} {1056.753296 344.839752} {1015.530884 351.817108}} size 43 angle 0.134001} 48609 {id 48609 c {962.427428 434.368246} p {{941.884705 454.018036} {986.398438 446.855377} {982.145691 415.507080} {938.896179 422.110199}} size 45 angle 0.159541} 48611 {id 48611 c {1138.240590 411.331288} p {{1119.195923 430.997711} {1164.848633 424.473511} {1155.939697 393.054352} {1111.961914 398.351746}} size 46 angle 0.141948} 48612 {id 48612 c {878.276910 515.929814} p {{855.905457 537.082336} {902.737427 530.844604} {900.828247 494.607208} {855.529419 502.059540}} size 47 angle 0.132415} 48614 {id 48614 c {1062.340061 487.695207} p {{1041.345215 509.091980} {1089.702148 502.621124} {1082.033081 467.625183} {1035.657471 473.139954}} size 48 angle 0.133024} 48617 {id 48617 c {977.755158 575.323222} p {{955.283936 598.861938} {1005.151978 591.779480} {999.932617 552.092224} {951.709961 559.678833}} size 50 angle 0.141080} 48619 {id 48619 c {1175.241702 547.766057} p {{1155.157227 570.688110} {1206.051147 564.145264} {1194.967285 525.253601} {1145.051514 531.716064}} size 51 angle 0.127857} 48600 {id 48600 c {869.726321 330.031056} p {{850.153198 347.147217} {890.231140 340.157562} {888.217468 313.861053} {849.431213 320.008118}} size 40 angle 0.172665} 48602 {id 48602 c {1027.292091 304.874545} p {{1009.680237 321.058594} {1050.356445 314.883850} {1045.061035 288.546143} {1005.118835 295.251953}} size 41 angle 0.150652} 48605 {id 48605 c {954.464210 373.169764} p {{932.091919 362.031342} {934.827820 391.160309} {977.714783 384.745453} {973.484131 355.744019}} size 29 angle -1.477147} 48607 {id 48607 c {1121.511416 347.373795} p {{1103.990112 365.026520} {1147.302490 359.805634} {1139.057983 329.695618} {1097.288696 335.697937}} size 43 angle 0.119962} 48608 {id 48608 c {874.893165 446.438284} p {{853.459473 466.811462} {898.051331 459.668365} {895.612122 426.744476} {852.912964 433.881165}} size 45 angle 0.158839} 48610 {id 48610 c {1049.016566 421.271853} p {{1029.286255 440.778168} {1074.801270 434.455658} {1068.158569 402.347168} {1023.870789 408.414734}} size 45 angle 0.138027} 48613 {id 48613 c {968.935134 500.034932} p {{943.878113 485.345337} {947.116699 521.777832} {995.350952 515.521118} {990.469421 478.575195}} size 36 angle -1.482137} 48615 {id 48615 c {1154.787958 474.180003} p {{1135.341919 495.410980} {1184.017578 489.054199} {1173.784912 453.439331} {1126.531982 459.801270}} size 49 angle 0.129860} 48616 {id 48616 c {880.531426 588.127394} p {{856.710999 611.316040} {906.284851 605.006714} {904.167236 565.118469} {855.683960 571.841858}} size 49 angle 0.126591} 48618 {id 48618 c {1075.733811 560.537017} p {{1054.046997 584.490234} {1104.965942 577.225769} {1096.608521 537.480774} {1047.277100 544.290955}} size 51 angle 0.141711}} imageName pose-1781543257841-7.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 158 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-3671321.265916 -136949.507711 2544618.126158 }{710108.103504 -4109714.560197 1388714.600088 }{203.442819 176.896104 872.758912 }} rmse 1.7736504896 tags {48601 {id 48601 c {642.392194 133.357953} p {{617.967773 158.737991} {672.279236 157.610672} {666.108459 108.713776} {612.277710 108.920670}} size 54 angle 0.020754} 48603 {id 48603 c {844.852518 132.784390} p {{822.703674 157.752472} {871.943237 155.121231} {865.329102 109.701424} {816.836548 109.684662}} size 49 angle 0.053387} 48604 {id 48604 c {544.373174 234.091164} p {{518.562195 260.513550} {575.344910 258.714539} {570.413330 207.434174} {512.823120 209.008011}} size 56 angle 0.031672} 48606 {id 48606 c {758.088901 229.356579} p {{735.210571 254.415009} {786.411987 252.761688} {780.482178 204.829422} {728.771057 205.129440}} size 51 angle 0.032279} 48609 {id 48609 c {665.531838 330.499630} p {{641.712585 356.745972} {695.350830 354.274567} {689.092102 304.538666} {635.630066 306.658691}} size 53 angle 0.046043} 48611 {id 48611 c {868.893259 319.759095} p {{847.957031 344.389862} {895.765808 342.600800} {889.633667 295.358704} {841.706055 296.649933}} size 47 angle 0.037404} 48612 {id 48612 c {567.420051 439.360050} p {{541.064819 468.426208} {599.423706 463.539520} {593.042664 411.101868} {535.535828 415.270813}} size 58 angle 0.083540} 48614 {id 48614 c {782.684121 422.996243} p {{759.732910 450.327362} {812.032654 445.964630} {805.213684 396.167236} {753.646423 400.271118}} size 52 angle 0.083225} 48617 {id 48617 c {690.240621 532.690635} p {{665.525635 561.614380} {720.572815 555.544250} {714.737122 504.022583} {659.297363 509.376617}} size 55 angle 0.109828} 48619 {id 48619 c {894.948644 511.727718} p {{873.199768 539.352783} {923.236877 534.105225} {916.227539 484.699615} {866.586121 489.291443}} size 50 angle 0.104491} 48600 {id 48600 c {534.750759 135.390685} p {{508.569702 161.553513} {566.256531 161.074783} {560.640137 109.519333} {502.975861 109.487190}} size 57 angle 0.008299} 48602 {id 48602 c {746.947710 134.937998} p {{723.971497 159.439575} {776.209045 159.769836} {769.576782 110.806610} {717.985352 110.359879}} size 52 angle -0.006322} 48605 {id 48605 c {655.668106 233.310392} p {{680.179504 207.696640} {624.799927 208.207703} {631.000854 259.087006} {685.842834 257.849152}} size 55 angle -3.132365} 48607 {id 48607 c {856.791753 227.330298} p {{835.554993 251.461700} {884.879150 251.208878} {878.426758 202.746368} {829.209656 203.881302}} size 49 angle 0.005126} 48608 {id 48608 c {556.857705 337.416902} p {{531.402344 365.235870} {588.602234 361.786133} {581.787415 310.172394} {524.963501 312.932770}} size 57 angle 0.060237} 48610 {id 48610 c {771.564042 327.611774} p {{749.380554 353.552917} {799.942505 350.367218} {793.670471 301.760742} {742.782227 304.532898}} size 50 angle 0.062923} 48613 {id 48613 c {680.121954 433.080485} p {{704.556458 405.732422} {649.144653 409.019745} {654.927063 461.279602} {711.183899 457.206970}} size 55 angle -3.082337} 48615 {id 48615 c {882.796758 417.159998} p {{860.786133 443.784180} {911.162842 440.625854} {903.889832 391.645691} {854.756836 393.963959}} size 50 angle 0.062612} 48616 {id 48616 c {580.346089 546.081070} p {{553.940918 575.834351} {612.320435 569.507202} {606.885620 516.176392} {547.775391 522.218018}} size 58 angle 0.107958} 48618 {id 48618 c {796.660210 523.128245} p {{773.319641 551.862793} {825.849243 545.705505} {819.719788 494.739624} {766.974731 500.166992}} size 52 angle 0.116683}} imageName pose-1781543257841-8.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 237 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1891.405861 1041.655384 2016.225692 }{520.247195 -2581.867798 882.220288 }{0.314318 0.305814 0.589245 }} rmse 3.33980752481 tags {48601 {id 48601 c {364.371225 154.206433} p {{331.795715 179.574631} {398.034821 189.569305} {395.756592 129.765060} {330.482635 118.607208}} size 66 angle -0.149758} 48603 {id 48603 c {596.617941 193.608417} p {{569.365417 215.626068} {621.879395 224.079178} {623.512268 171.880157} {570.107422 161.631012}} size 53 angle -0.159600} 48604 {id 48604 c {233.031368 256.033977} p {{198.913910 282.412262} {268.121460 288.495392} {267.337982 229.509445} {195.164581 221.003876}} size 69 angle -0.087672} 48606 {id 48606 c {486.550832 282.978654} p {{457.602051 306.474640} {514.791077 312.368927} {514.793640 260.055664} {457.518707 252.764252}} size 57 angle -0.102704} 48609 {id 48609 c {369.163334 379.775009} p {{338.807770 404.953491} {400.322906 407.798096} {398.998322 355.028320} {336.650604 350.534973}} size 61 angle -0.046209} 48611 {id 48611 c {592.702856 393.589059} p {{566.986328 416.086365} {617.135071 418.671417} {617.891846 371.553253} {567.347168 367.558655}} size 50 angle -0.051502} 48612 {id 48612 c {245.957694 484.046393} p {{212.855713 511.161255} {280.776245 510.973358} {278.629791 457.283661} {209.693771 456.001648}} size 67 angle 0.002766} 48614 {id 48614 c {487.158600 485.320641} p {{459.366730 509.293365} {514.243896 509.179474} {514.503540 461.733429} {459.173187 460.668915}} size 54 angle 0.002075} 48617 {id 48617 c {375.237326 583.398845} p {{345.979401 609.102905} {405.023529 605.900635} {403.759338 558.341309} {344.480438 560.163757}} size 59 angle 0.054182} 48619 {id 48619 c {587.942277 574.730119} p {{563.161377 597.582275} {610.900452 594.895813} {611.961670 552.580200} {564.200806 553.876404}} size 47 angle 0.056215} 48600 {id 48600 c {226.374950 127.267377} p {{189.934280 153.998489} {264.650635 164.867844} {262.333344 100.890038} {186.153687 87.755653}} size 75 angle -0.144462} 48602 {id 48602 c {486.868933 171.379722} p {{455.991943 194.898392} {516.005554 204.446930} {517.362671 148.152969} {456.641235 137.074249}} size 60 angle -0.157784} 48605 {id 48605 c {365.335940 265.382087} p {{397.465179 297.087921} {397.123322 241.078461} {331.988190 232.473801} {333.097260 290.030762}} size 56 angle 1.576900} 48607 {id 48607 c {593.918332 292.977820} p {{567.305542 315.167755} {617.385620 319.511688} {620.053650 271.186005} {568.262878 263.969849}} size 50 angle -0.086523} 48608 {id 48608 c {236.291299 366.820416} p {{202.024750 393.381042} {272.369934 397.377472} {269.129639 341.366821} {198.805801 335.071808}} size 70 angle -0.056751} 48610 {id 48610 c {486.311857 383.896561} p {{457.866730 407.818268} {514.040649 410.630219} {514.123901 360.507263} {457.134186 355.766022}} size 56 angle -0.050016} 48613 {id 48613 c {370.907103 480.363625} p {{402.015625 506.210236} {401.381683 455.518799} {338.221100 453.206360} {339.819580 505.708160}} size 50 angle 1.583302} 48615 {id 48615 c {588.610704 483.153853} p {{563.043274 506.112549} {612.937317 506.486633} {613.698975 460.625427} {563.892517 459.445496}} size 49 angle -0.007497} 48616 {id 48616 c {247.747799 583.097366} p {{215.949295 610.146484} {282.119080 607.427429} {278.761658 556.715698} {212.549408 558.181824}} size 66 angle 0.041069} 48618 {id 48618 c {485.557389 575.696389} p {{458.575623 599.804138} {511.779755 597.280396} {512.143311 551.942322} {458.491974 553.418457}} size 53 angle 0.047400}} imageName pose-1781543257841-9.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 271 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-263.442465 -3993.519151 3622.146186 }{3838.120310 362.146076 1127.873075 }{-0.281576 0.033683 0.956437 }} rmse 2.30152949436 tags {48601 {id 48601 c {198.621573 241.319812} p {{222.522720 260.372314} {216.912018 217.634796} {174.017868 221.707275} {181.274582 263.783112}} size 43 angle 1.701333} 48603 {id 48603 c {170.962676 67.695843} p {{197.280319 89.311028} {187.799377 43.787811} {145.962463 47.162689} {153.747971 92.140640}} size 46 angle 1.776127} 48604 {id 48604 c {293.592474 318.039051} p {{317.013885 337.112396} {311.371521 295.126556} {269.805115 298.667694} {276.050354 340.646210}} size 42 angle 1.704383} 48606 {id 48606 c {270.454320 148.843220} p {{295.507935 169.239349} {289.732910 124.954781} {245.201157 128.284637} {251.416473 172.433350}} size 44 angle 1.700472} 48609 {id 48609 c {365.796203 226.761980} p {{389.959595 246.366608} {384.328979 203.366684} {341.377594 206.950287} {347.695770 249.611496}} size 43 angle 1.701000} 48611 {id 48611 c {342.683495 55.350728} p {{366.480438 74.572601} {360.948029 32.722778} {317.286224 34.836197} {324.416443 77.981796}} size 42 angle 1.702231} 48612 {id 48612 c {460.969073 304.179221} p {{484.815125 323.147705} {479.274994 281.422089} {436.590271 284.786957} {443.134369 326.350555}} size 42 angle 1.702800} 48614 {id 48614 c {438.893249 134.686283} p {{463.889557 155.440750} {457.597778 110.989212} {414.331299 114.292465} {420.062805 158.542877}} size 44 angle 1.711405} 48617 {id 48617 c {533.080383 213.173669} p {{557.535583 233.393188} {551.556335 189.925522} {509.016449 193.277649} {514.665344 236.345169}} size 43 angle 1.707495} 48619 {id 48619 c {511.162161 40.181078} p {{535.220459 60.709080} {529.012695 17.277449} {487.738098 20.194244} {492.589447 64.011322}} size 43 angle 1.712767} 48602 {id 48602 c {183.638056 152.018918} p {{209.137878 172.819244} {202.462860 127.247940} {158.109695 131.195312} {165.382980 176.040207}} size 46 angle 1.716236} 48605 {id 48605 c {280.437145 231.136902} p {{261.948456 254.223755} {304.560974 250.985748} {299.074646 207.864227} {256.200226 211.195007}} size 42 angle 0.075841} 48607 {id 48607 c {255.648743 58.022969} p {{280.276367 78.527657} {273.481659 34.840279} {230.918121 37.432526} {237.351044 81.809875}} size 44 angle 1.725090} 48608 {id 48608 c {374.839880 308.191019} p {{398.570862 327.621948} {393.538696 285.166840} {350.828522 288.530518} {356.646088 330.593353}} size 42 angle 1.688775} 48610 {id 48610 c {353.426549 139.437219} p {{378.838562 160.236038} {372.627075 115.518738} {328.744843 119.236130} {334.531097 162.975662}} size 45 angle 1.708819} 48613 {id 48613 c {447.986478 217.436763} p {{429.169769 240.373611} {472.259338 237.322754} {467.006531 194.252045} {423.699921 197.539551}} size 43 angle 0.070685} 48615 {id 48615 c {425.381881 44.997536} p {{449.748932 65.453217} {443.391968 21.960690} {402.644073 25.909575} {406.869446 68.676941}} size 43 angle 1.715931} 48616 {id 48616 c {542.267473 295.145410} p {{565.842590 314.410583} {560.579468 272.551575} {518.264099 275.530273} {524.113098 317.544769}} size 42 angle 1.695874} 48618 {id 48618 c {520.425825 125.529852} p {{545.750671 146.685135} {538.838501 101.829994} {496.323822 105.396080} {501.663605 149.679626}} size 45 angle 1.723693}} imageName pose-1781543257841-10.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 286 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{50.824095 -712.814483 1047.080530 }{1220.638908 279.244176 172.091587 }{-0.050051 0.134620 0.274120 }} rmse 1.70201751052 tags {48601 {id 48601 c {72.271242 414.743317} p {{109.223740 440.646667} {102.671288 390.229553} {35.977558 389.301788} {40.616467 440.268860}} size 50 angle 1.700037} 48603 {id 48603 c {54.034779 217.560069} p {{89.145515 245.273972} {86.687927 196.433075} {16.739708 188.122009} {21.451021 238.642166}} size 48 angle 1.621072} 48604 {id 48604 c {205.449907 509.739067} p {{237.443558 532.384338} {232.669586 485.308655} {172.757889 486.599487} {177.778259 534.575134}} size 47 angle 1.671861} 48606 {id 48606 c {186.127986 322.854836} p {{216.630951 347.064301} {212.562012 302.016602} {154.300674 297.594269} {158.851440 344.357239}} size 45 angle 1.660877} 48609 {id 48609 c {307.253575 416.963510} p {{337.794800 439.960144} {330.584656 395.770905} {277.674011 394.690979} {282.244781 439.680054}} size 44 angle 1.732536} 48611 {id 48611 c {287.998633 243.027042} p {{315.487518 266.903290} {311.848602 224.639084} {259.013916 217.851547} {263.363373 262.020447}} size 42 angle 1.656684} 48612 {id 48612 c {417.887151 502.336126} p {{444.486633 522.683228} {439.543701 480.797607} {390.688629 481.530792} {395.722961 524.379517}} size 42 angle 1.688263} 48614 {id 48614 c {397.370296 335.164383} p {{424.254028 357.527649} {418.144684 316.253967} {370.656311 312.942322} {375.638885 354.945953}} size 41 angle 1.717750} 48617 {id 48617 c {499.446103 419.795104} p {{524.130798 440.142609} {518.483093 400.440186} {474.786102 399.467957} {479.741669 439.828613}} size 40 angle 1.712099} 48619 {id 48619 c {479.151452 262.342380} p {{503.282379 284.006531} {498.348785 245.130402} {454.578003 240.280945} {459.620728 279.853271}} size 39 angle 1.697027} 48600 {id 48600 c {77.699261 512.609928} p {{113.413376 536.890869} {108.199699 486.683990} {41.208942 487.801270} {46.064499 539.500061}} size 50 angle 1.674269} 48605 {id 48605 c {193.944591 415.181222} p {{161.437576 390.916840} {165.369568 439.293060} {226.656128 439.598267} {220.324692 392.921478}} size 48 angle -1.489695} 48607 {id 48607 c {176.552192 230.694903} p {{207.905884 256.611755} {204.110565 210.874542} {143.436234 203.321365} {148.534119 250.845886}} size 45 angle 1.653588} 48608 {id 48608 c {313.934619 506.088315} p {{344.029724 528.150574} {338.209686 483.178070} {283.309875 483.637787} {288.532684 530.062073}} size 45 angle 1.699494} 48610 {id 48610 c {296.282791 329.818533} p {{325.236298 353.672607} {320.333221 310.113373} {267.727356 306.292419} {271.577606 350.060150}} size 43 angle 1.682886} 48613 {id 48613 c {406.646786 419.554464} p {{379.693573 397.918732} {383.775238 440.470154} {433.692444 441.264404} {428.465881 399.601227}} size 42 angle -1.475166} 48615 {id 48615 c {388.513550 253.961729} p {{414.263428 276.515167} {410.385437 236.083435} {362.790558 231.431839} {366.332153 272.093018}} size 40 angle 1.666418} 48616 {id 48616 c {507.837697 501.472006} p {{532.209351 521.014099} {527.509155 481.012390} {482.639832 481.267426} {487.555908 522.566406}} size 40 angle 1.687760} 48618 {id 48618 c {488.165975 341.681269} p {{513.142700 363.443085} {506.917389 323.423706} {463.470276 320.164307} {468.794586 360.542480}} size 40 angle 1.725117}} imageName pose-1781543257841-11.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 310 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{766892.576057 -19515.503279 451640.762142 }{23960.984967 703560.433782 93720.310217 }{49.603996 -23.693156 159.828412 }} rmse 1.83027038725 tags {48601 {id 48601 c {432.038537 553.445692} p {{449.389191 528.153564} {414.490356 532.363770} {415.014954 578.261047} {449.635620 574.586365}} size 35 angle -3.021533} 48603 {id 48603 c {302.262651 569.126614} p {{318.298492 545.140564} {285.711456 548.772949} {287.065430 591.858276} {318.288391 588.834106}} size 32 angle -3.030584} 48604 {id 48604 c {500.794313 450.427968} p {{519.482239 422.830261} {481.857849 429.776672} {483.057526 476.621063} {519.694641 471.039856}} size 38 angle -2.959023} 48606 {id 48606 c {365.341744 472.858152} p {{381.949127 447.837952} {349.402557 453.597107} {349.204224 497.170471} {381.573456 492.472687}} size 33 angle -2.966454} 48609 {id 48609 c {429.053209 371.806219} p {{445.609863 345.667053} {411.475128 352.892456} {412.795074 397.474091} {446.470551 390.547028}} size 34 angle -2.932999} 48611 {id 48611 c {302.674349 398.168756} p {{316.837280 373.322449} {289.007324 380.852509} {288.867432 422.390503} {316.956909 416.264893}} size 28 angle -2.877346} 48612 {id 48612 c {496.276042 264.759201} p {{513.637085 237.214569} {477.861755 246.603622} {479.160706 291.914001} {514.729065 282.952972}} size 36 angle -2.884936} 48614 {id 48614 c {363.212078 299.003323} p {{379.272125 273.819183} {347.609619 282.036316} {347.335876 323.899170} {379.685486 316.917450}} size 32 angle -2.887672} 48617 {id 48617 c {427.922356 195.767095} p {{445.219391 168.574158} {411.057007 178.722443} {411.071198 222.259064} {444.654907 212.677536}} size 35 angle -2.852835} 48619 {id 48619 c {304.872502 233.641435} p {{319.946808 208.123108} {291.097809 217.632965} {290.434784 258.082123} {318.112488 249.028488}} size 30 angle -2.823167} 48600 {id 48600 c {501.221953 543.284653} p {{520.159790 516.529175} {482.061554 521.702759} {482.690491 569.466003} {521.101440 565.676514}} size 38 angle -3.006622} 48602 {id 48602 c {362.055178 560.390636} p {{378.363037 535.925354} {345.495270 539.720520} {345.660431 584.986267} {378.310333 580.680359}} size 33 angle -3.026634} 48605 {id 48605 c {428.911134 460.333650} p {{411.418060 485.897827} {447.390472 480.925568} {447.014984 433.876892} {411.214752 440.614197}} size 36 angle 0.137354} 48607 {id 48607 c {299.170137 480.372077} p {{315.152313 456.267578} {284.449646 461.873840} {283.119354 504.580048} {315.378815 500.740417}} size 31 angle -2.960984} 48608 {id 48608 c {497.456230 354.845126} p {{515.249817 326.969238} {479.143768 336.376831} {479.984161 382.217316} {516.885071 374.439301}} size 37 angle -2.886705} 48610 {id 48610 c {362.066778 384.370008} p {{378.052521 358.907959} {345.932373 365.576324} {346.316467 409.457062} {378.003723 402.933685}} size 32 angle -2.936894} 48613 {id 48613 c {426.550325 281.249530} p {{409.839600 307.328125} {444.106659 299.489532} {443.746246 254.413742} {409.587128 263.625763}} size 35 angle 0.224881} 48616 {id 48616 c {495.222277 174.174471} p {{513.788574 145.978683} {477.288757 157.132172} {477.218567 201.515884} {513.863220 191.889038}} size 38 angle -2.845028} 48618 {id 48618 c {362.450130 213.833265} p {{379.252136 187.789291} {346.920319 197.150696} {346.528229 238.513031} {378.182556 230.733490}} size 33 angle -2.859758}} imageName pose-1781543257841-12.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 336 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{4603.471570 134559.198783 47159.825235 }{-135326.500196 5334.233566 57404.380517 }{-0.661932 0.140649 30.635474 }} rmse 1.34260804628 tags {48601 {id 48601 c {1073.750515 175.041853} p {{1052.528687 157.187790} {1052.229614 193.388962} {1095.322754 193.190720} {1094.947021 156.971298}} size 36 angle -1.579058} 48603 {id 48603 c {1074.066976 324.507615} p {{1052.206787 305.428101} {1052.459229 343.463501} {1096.251709 343.870392} {1096.289062 305.012787}} size 38 angle -1.564159} 48604 {id 48604 c {991.370515 107.495040} p {{971.912415 90.922264} {970.732605 125.059685} {1012.167603 125.208252} {1012.146545 89.812843}} size 34 angle -1.605343} 48606 {id 48606 c {988.277975 249.339919} p {{967.488159 230.941681} {966.608826 267.273804} {1009.637512 268.242340} {1010.369141 231.056763}} size 36 angle -1.594994} 48609 {id 48609 c {907.009210 175.727970} p {{887.060913 157.463745} {885.001831 193.691315} {927.278198 194.285812} {928.883423 157.873322}} size 36 angle -1.627573} 48611 {id 48611 c {899.603721 323.934888} p {{878.815857 303.766144} {877.170288 343.879761} {920.487305 344.196503} {922.151794 303.888092}} size 40 angle -1.611796} 48612 {id 48612 c {829.132043 104.562774} p {{810.125427 86.692841} {807.380005 121.667053} {848.812683 123.066422} {850.246216 87.960068}} size 35 angle -1.649134} 48614 {id 48614 c {818.998538 247.498701} p {{798.753723 228.354401} {796.158691 265.858429} {838.737915 266.165039} {841.599487 229.331009}} size 37 angle -1.639880} 48617 {id 48617 c {741.013150 172.140930} p {{721.825806 153.315475} {717.891663 189.537949} {760.464600 191.225510} {763.652710 155.106522}} size 36 angle -1.678983} 48619 {id 48619 c {725.870029 321.457629} p {{706.293152 301.516876} {702.403625 340.028595} {745.532410 341.485474} {749.751099 302.558502}} size 38 angle -1.671451} 48600 {id 48600 c {1074.052102 105.429277} p {{1053.495850 88.308304} {1053.453979 123.142807} {1095.533203 123.320541} {1094.498901 87.845879}} size 34 angle -1.571998} 48602 {id 48602 c {1075.037272 247.719933} p {{1052.954712 228.852646} {1053.197266 266.806152} {1097.088257 266.560242} {1096.558472 228.912323}} size 37 angle -1.564406} 48605 {id 48605 c {991.462856 176.293567} p {{970.636841 157.802673} {969.213196 195.071320} {1012.382080 194.867218} {1013.173828 157.970444}} size 37 angle -1.608977} 48607 {id 48607 c {988.271297 323.409970} p {{966.160828 303.230164} {965.943604 343.330688} {1010.088562 343.322174} {1010.208191 303.837921}} size 40 angle -1.576213} 48608 {id 48608 c {911.985226 106.559502} p {{891.915039 88.722786} {890.529480 123.506119} {931.588745 123.981483} {933.158203 89.836227}} size 34 angle -1.610609} 48610 {id 48610 c {904.876075 247.834935} p {{884.256775 228.930695} {882.191711 266.480865} {925.678406 266.906982} {927.533142 229.211441}} size 37 angle -1.625736} 48613 {id 48613 c {825.474011 173.685320} p {{805.874146 155.010681} {802.850891 191.792252} {845.849548 193.099014} {848.043945 155.620956}} size 36 angle -1.652807} 48615 {id 48615 c {814.123097 321.664336} p {{793.880493 301.762512} {790.620117 341.099457} {835.070190 342.258789} {837.308655 302.491699}} size 39 angle -1.653491} 48616 {id 48616 c {749.620519 102.389401} p {{730.910706 84.664383} {727.124084 119.449913} {768.818787 120.577164} {771.829041 85.547234}} size 34 angle -1.679226} 48618 {id 48618 c {735.360506 244.450282} p {{715.602051 225.177017} {711.425720 262.848114} {755.005920 263.613281} {758.853516 226.392029}} size 37 angle -1.681208}} imageName pose-1781543257841-13.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 349 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-42006.056341 618407.989571 46334.318232 }{-565093.723952 -27983.125273 251552.732742 }{26.922105 54.178774 129.547352 }} rmse 0.738898030151 tags {48601 {id 48601 c {1583.305303 145.282432} p {{1553.724854 133.092209} {1563.607910 174.091873} {1613.596924 157.765732} {1603.335205 115.986664}} size 42 angle -1.334257} 48603 {id 48603 c {1623.495857 309.412621} p {{1593.311890 295.631622} {1603.908203 336.235626} {1654.117798 323.393585} {1643.897461 281.475006}} size 41 angle -1.315523} 48604 {id 48604 c {1471.273914 100.575907} p {{1445.189575 90.033272} {1453.117554 128.696182} {1499.084229 111.816139} {1489.562866 72.250275}} size 39 angle -1.368546} 48606 {id 48606 c {1507.686781 256.319445} p {{1479.963989 243.632904} {1489.166260 282.961151} {1535.705322 269.141327} {1526.807739 228.814011}} size 40 angle -1.340945} 48609 {id 48609 c {1401.802316 207.969095} p {{1376.445190 196.288300} {1384.526978 234.246750} {1427.940308 220.009598} {1419.446411 181.130524}} size 38 angle -1.361017} 48611 {id 48611 c {1435.122709 360.461753} p {{1409.137939 346.993469} {1417.652100 385.808502} {1461.908081 374.345001} {1452.723511 334.926117}} size 39 angle -1.354864} 48612 {id 48612 c {1304.792060 163.544640} p {{1281.339722 152.543762} {1288.938965 189.175308} {1328.660156 174.740540} {1320.708984 137.810776}} size 37 angle -1.366247} 48614 {id 48614 c {1335.437698 309.322675} p {{1311.624146 297.276917} {1319.497681 333.455688} {1359.369629 321.428314} {1351.731812 284.653564}} size 37 angle -1.356509} 48617 {id 48617 c {1243.749759 262.137148} p {{1221.931274 250.747498} {1228.881592 285.992737} {1265.767822 273.630981} {1258.832153 237.937836}} size 35 angle -1.376096} 48619 {id 48619 c {1272.913442 404.925019} p {{1250.692993 392.101196} {1257.740112 428.166321} {1295.694092 418.072144} {1288.293701 381.366760}} size 36 angle -1.377828} 48600 {id 48600 c {1564.066360 65.587149} p {{1535.401978 54.913307} {1544.859375 94.562202} {1593.631592 76.596443} {1583.183472 36.747677}} size 40 angle -1.336643} 48602 {id 48602 c {1603.038917 226.582457} p {{1572.679565 213.412918} {1582.847534 254.925323} {1633.826782 239.937881} {1623.557983 197.779617}} size 42 angle -1.330587} 48605 {id 48605 c {1488.559622 178.892756} p {{1469.938721 206.515533} {1516.978638 191.118256} {1507.937988 150.146332} {1460.885254 166.987595}} size 49 angle 0.316332} 48607 {id 48607 c {1526.241290 334.702058} p {{1498.980103 321.365814} {1506.401367 362.501465} {1555.100708 348.820160} {1545.040161 308.361359}} size 41 angle -1.392307} 48608 {id 48608 c {1384.624545 133.919279} p {{1359.451660 122.670517} {1367.424805 161.219101} {1410.523193 145.492355} {1401.587036 106.996025}} size 39 angle -1.366839} 48610 {id 48610 c {1417.455410 284.507754} p {{1391.823120 272.121887} {1400.070435 310.095215} {1443.510010 297.097687} {1435.313721 258.223633}} size 38 angle -1.356931} 48613 {id 48613 c {1319.617852 236.336932} p {{1303.319336 261.778351} {1343.896973 248.560242} {1336.254272 210.368057} {1295.936890 224.414764}} size 42 angle 0.314909} 48615 {id 48615 c {1350.581998 384.136254} p {{1326.474976 370.715607} {1334.264893 408.357025} {1375.247803 397.867981} {1367.291260 359.333374}} size 38 angle -1.366726} 48616 {id 48616 c {1229.578846 191.805533} p {{1207.622070 180.703964} {1214.551758 216.823944} {1252.010010 203.146957} {1244.745361 166.554993}} size 36 angle -1.381248} 48618 {id 48618 c {1258.106145 333.438437} p {{1236.033203 321.214142} {1243.164917 356.981049} {1280.836792 346.026978} {1273.311035 309.480377}} size 36 angle -1.373983}} imageName pose-1781543257841-14.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg}}} {}}
when the collected results for {/any/ claims a calibration from camera /cam/ to display monitor is /a (
[ m23659:0 (s31348:0) ]
[ m23661:0 () ]
)when the collected results for {/any/ claims a calibration from camera /cam/ to display monitor is /anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n} with environment {{this builtin-programs/calibrate/load-calibration.folk} {} {} {disp monitor displayWidth 4096 displayHeight 2160} {}}
when the collected results for {/any/ wishes program 62 does not run} are /__results/ {if {[llength $ (
[ m47950:639 (s15553:765) ]
[ m47955:639 (s15562:766 s15565:766) ]
)when the collected results for {/any/ wishes program 62 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 62 programCode {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 8
}} {}}
when the collected results for {/any/ wishes program 62 is replaced with /...anything/} are /__result (
[ m48152:643 (s15791:764) ]
[ m48158:643 () ]
)when the collected results for {/any/ wishes program 62 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 62 programCode {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 8
}} {} {__results {}} {}}
when the collected results for {/any/ wishes program 11 does not run} are /__results/ {if {[llength $ (
[ m33930:725 (s14337:865) ]
[ m33932:727 (s14341:866 s14344:854) ]
)when the collected results for {/any/ wishes program 11 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 11 programCode {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}} {}}
when the collected results for {/any/ wishes program 11 is replaced with /...anything/} are /__result (
[ m33936:727 (s14345:852) ]
[ m33941:727 (s14352:864) ]
)when the collected results for {/any/ wishes program 11 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 11 programCode {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}} {} {__results {}} {}}
when the collected results for {/someone/ claims tag 11 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m25655:915 (s2785:1088) ]
[ m25660:915 (s2792:1088 s2793:1088 s14279:866 s2796:1088) ]
)when the collected results for {/someone/ claims tag 11 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 11} {}}
when the collected results for {/someone/ wishes 11 is labelled /text/ with /...options/} are /result (
[ m25755:915 (s2896:1088) ]
[ m25761:915 () ]
)when the collected results for {/someone/ wishes 11 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 11 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when the collected results for {/someone/ claims tag 82 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m6393:988 (s52872:1175) ]
[ m6396:990 () ]
[ m6667:985 (s53216:1172 s53218:1174 s38504:827 s53221:1172) ]
)when the collected results for {/someone/ claims tag 82 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 82} {}}
when the collected results for {/any/ wishes program 54 does not run} are /__results/ {if {[llength $ (
[ m6510:990 (s53023:1175) ]
[ m6514:983 (s53029:1175 s53031:1175) ]
)when the collected results for {/any/ wishes program 54 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 54 programCode set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {}}
when the collected results for {/any/ wishes program 54 is replaced with /...anything/} are /__result (
[ m6580:989 (s53122:1174) ]
[ m6589:990 () ]
)when the collected results for {/any/ wishes program 54 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 54 programCode set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when the collected results for {/any/ wishes program 82 does not run} are /__results/ {if {[llength $ (
[ m6719:990 (s53277:1175) ]
[ m6723:990 (s53280:1175 s53284:1175) ]
)when the collected results for {/any/ wishes program 82 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 82 programCode When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n} {}}
when the collected results for {/any/ wishes program 82 is replaced with /...anything/} are /__result (
[ m6727:990 (s53288:1174) ]
[ m6732:978 (s53295:1175) ]
)when the collected results for {/any/ wishes program 82 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 82 programCode When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n} {} {__results {}} {}}
when the collected results for {/someone/ wishes 82 is labelled /text/ with /...options/} are /result (
[ m6750:989 (s53314:1175) ]
[ m23687:1052 () ]
[ m23979:1062 () ]
[ m24014:1064 () ]
[ m24165:1067 () ]
[ m24187:1065 () ]
[ m24236:1054 () ]
[ m24287:1065 (s5489:1263) ]
)when the collected results for {/someone/ wishes 82 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 82 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}} {}}
when the collected results for {/someone/ claims tag 62 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m3058:1023 (s31838:1214) ]
[ m3060:1024 (s31841:1214 s31842:1146 s55973:746 s31844:1157) ]
)when the collected results for {/someone/ claims tag 62 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 62} {}}
when the collected results for {/someone/ wishes 62 is labelled /text/ with /...options/} are /result (
[ m3089:1023 (s31882:1214) ]
[ m3092:1024 () ]
)when the collected results for {/someone/ wishes 62 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 62 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when the collected results for {/any/ wishes program 63 does not run} are /__results/ {if {[llength $ (
[ m3371:1022 (s32222:1206) ]
[ m3373:1022 (s32225:1215 s32226:1215) ]
)when the collected results for {/any/ wishes program 63 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 63 programCode {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}} {}}
when the collected results for {/any/ wishes program 63 is replaced with /...anything/} are /__result (
[ m3374:1022 (s32227:1210) ]
[ m3377:1022 (s32229:1205) ]
)when the collected results for {/any/ wishes program 63 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 63 programCode {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}} {} {__results {}} {}}
when the collected results for {/someone/ wishes 54-display is titled /text/} are /results/ \n\ \ \ \ (
[ m44376:1033 (s51534:1233) ]
[ m44382:1038 () ]
)when the collected results for {/someone/ wishes 54-display is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-display} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-display is footnoted /text/} are /results/ \n\ \ (
[ m44372:1038 (s51526:1233) ]
[ m44374:1032 () ]
)when the collected results for {/someone/ wishes 54-display is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-display} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-display is right-margined /text/} are /results/ \ (
[ m44365:1037 (s51515:1233) ]
[ m44369:1037 () ]
)when the collected results for {/someone/ wishes 54-display is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-display} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-display is left-margined /text/} are /results/ \n (
[ m44358:1038 (s51509:1233) ]
[ m44363:1037 () ]
)when the collected results for {/someone/ wishes 54-display is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-display} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ claims tag 63 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m44638:1036 (s51834:1229) ]
[ m44641:1039 (s51838:1229 s51840:1232 s12973:51 s51843:1233) ]
)when the collected results for {/someone/ claims tag 63 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 63} {}}
when the collected results for {/someone/ wishes 63 is labelled /text/ with /...options/} are /result (
[ m44683:1039 (s51883:1214) ]
[ m44688:1038 () ]
)when the collected results for {/someone/ wishes 63 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 63 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when the collected results for {/someone/ wishes 62 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m16202:1053 (s40297:1249) ]
[ m16205:1052 (s40302:1249) ]
)when the collected results for {/someone/ wishes 62 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 62} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 62 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m16198:1051 (s40294:1249) ]
[ m16201:1052 () ]
)when the collected results for {/someone/ wishes 62 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 62} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 62 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m16192:1052 (s40289:1247) ]
[ m16196:1053 () ]
)when the collected results for {/someone/ wishes 62 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 62} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 62 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m16188:1051 (s40285:1248) ]
[ m16190:1051 () ]
)when the collected results for {/someone/ wishes 62 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 62} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 63 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m16463:1052 (s40615:1194) ]
[ m16469:1052 () ]
)when the collected results for {/someone/ wishes 63 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 63} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 63 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m16473:1048 (s40625:1248) ]
[ m16478:1053 () ]
)when the collected results for {/someone/ wishes 63 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 63} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 63 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m16464:1052 (s40616:1249) ]
[ m16470:1049 () ]
)when the collected results for {/someone/ wishes 63 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 63} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 63 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m16434:1050 (s40582:1195) ]
[ m16461:1048 () ]
)when the collected results for {/someone/ wishes 63 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 63} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {folk-sva has display /display/ with /...opts/} are /results/ {apply { (
[ m61802:1035 (s49323:1251) ]
[ m61805:1036 (s49334:1249) ]
)when the collected results for {folk-sva has display /display/ with /...opts/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {folk-sva has display /display/ with /...opts/} \n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses display mon (
[ m61821:1036 () ]
[ m61839:1041 () ]
[ m61855:1031 (s49340:1241) ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} \n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {__ref s1888:0 display monitor opts {info {name {monitor} physicalDimensions {1016 571} physicalResolution {3840 2160} modes {{visibleRegion {3840 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 59940} {visibleRegion {4096 2160} refreshRate 50000} {visibleRegion {4096 2160} refreshRate 30000} {visibleRegion {4096 2160} refreshRate 29970} {visibleRegion {4096 2160} refreshRate 25000} {visibleRegion {4096 2160} refreshRate 24000} {visibleRegion {4096 2160} refreshRate 23976} {visibleRegion {3840 2160} refreshRate 59940} {visibleRegion {3840 2160} refreshRate 50000} {visibleRegion {3840 2160} refreshRate 30000} {visibleRegion {3840 2160} refreshRate 29970} {visibleRegion {3840 2160} refreshRate 25000} {visibleRegion {3840 2160} refreshRate 24000} {visibleRegion {3840 2160} refreshRate 23976} {visibleRegion {2288 1430} refreshRate 61015} {visibleRegion {1920 1200} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 240000} {visibleRegion {1920 1080} refreshRate 120000} {visibleRegion {1920 1080} refreshRate 119880} {visibleRegion {1920 1080} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 59940} {visibleRegion {1920 1080} refreshRate 50000} {visibleRegion {1920 1080} refreshRate 30000} {visibleRegion {1920 1080} refreshRate 29970} {visibleRegion {1920 1080} refreshRate 24000} {visibleRegion {1920 1080} refreshRate 23976} {visibleRegion {1600 1200} refreshRate 60000} {visibleRegion {1680 1050} refreshRate 60000} {visibleRegion {1280 1024} refreshRate 60000} {visibleRegion {1440 900} refreshRate 60000} {visibleRegion {1280 800} refreshRate 60000} {visibleRegion {1280 720} refreshRate 60000} {visibleRegion {1280 720} refreshRate 59940} {visibleRegion {1280 720} refreshRate 50000} {visibleRegion {1024 768} refreshRate 60000} {visibleRegion {800 600} refreshRate 60000} {visibleRegion {720 576} refreshRate 50000} {visibleRegion {720 480} refreshRate 60000} {visibleRegion {720 480} refreshRate 59940} {visibleRegion {640 480} refreshRate 60000} {visibleRegion {640 480} refreshRate 59940}}}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses display mon (
[ m61815:1045 (s49340:1241) ]
[ m61818:1049 () ]
[ m61830:1055 () ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} \n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {display monitor opts {info {name {monitor} physicalDimensions {1016 571} physicalResolution {3840 2160} modes {{visibleRegion {3840 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 59940} {visibleRegion {4096 2160} refreshRate 50000} {visibleRegion {4096 2160} refreshRate 30000} {visibleRegion {4096 2160} refreshRate 29970} {visibleRegion {4096 2160} refreshRate 25000} {visibleRegion {4096 2160} refreshRate 24000} {visibleRegion {4096 2160} refreshRate 23976} {visibleRegion {3840 2160} refreshRate 59940} {visibleRegion {3840 2160} refreshRate 50000} {visibleRegion {3840 2160} refreshRate 30000} {visibleRegion {3840 2160} refreshRate 29970} {visibleRegion {3840 2160} refreshRate 25000} {visibleRegion {3840 2160} refreshRate 24000} {visibleRegion {3840 2160} refreshRate 23976} {visibleRegion {2288 1430} refreshRate 61015} {visibleRegion {1920 1200} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 240000} {visibleRegion {1920 1080} refreshRate 120000} {visibleRegion {1920 1080} refreshRate 119880} {visibleRegion {1920 1080} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 59940} {visibleRegion {1920 1080} refreshRate 50000} {visibleRegion {1920 1080} refreshRate 30000} {visibleRegion {1920 1080} refreshRate 29970} {visibleRegion {1920 1080} refreshRate 24000} {visibleRegion {1920 1080} refreshRate 23976} {visibleRegion {1600 1200} refreshRate 60000} {visibleRegion {1680 1050} refreshRate 60000} {visibleRegion {1280 1024} refreshRate 60000} {visibleRegion {1440 900} refreshRate 60000} {visibleRegion {1280 800} refreshRate 60000} {visibleRegion {1280 720} refreshRate 60000} {visibleRegion {1280 720} refreshRate 59940} {visibleRegion {1280 720} refreshRate 50000} {visibleRegion {1024 768} refreshRate 60000} {visibleRegion {800 600} refreshRate 60000} {visibleRegion {720 576} refreshRate 50000} {visibleRegion {720 480} refreshRate 60000} {visibleRegion {720 480} refreshRate 59940} {visibleRegion {640 480} refreshRate 60000} {visibleRegion {640 480} refreshRate 59940}}}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {folk-sva has camera /camera/ with /...opts/} are /results/ {apply {{p (
[ m61857:1044 (s49385:1248) ]
[ m61861:1044 (s49409:1250 s49418:1249) ]
)when the collected results for {folk-sva has camera /camera/ with /...opts/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {folk-sva has camera /camera/ with /...opts/} \n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev (
[ m61895:974 (s49434:1249) ]
[ m61906:1054 () ]
[ m61923:1053 () ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} {
set isUsingCamera $([llength $results] >= 1)
if {$isUsingCamera} {
set usingOpts [dict get [lindex $results 0] usingOpts]
}
set resolutions [list]
foreach format [dict get $opts formats] {
# For now, we only support MJPG. The more raw formats are
# rarely used by cameras at even medium resolutions and
# framerates, anyway, so it's only worth supporting MJPG.
if {$format(fourcc) eq "MJPG"} {
lappend resolutions {*}$format(resolutions)
}
}
set resolutions [lsort -command {apply {{a b} {
expr {[dict get $b width] - [dict get $a width]}
}}} $resolutions]
if {[llength $resolutions] == 0} {
# Cameras often have extra camera devices with no formats (or no
# MJPG, at least) for some reason. Not very useful for us.
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)<br>
(no supported formats)
</div>
}
} else {
set cameraId [string map {/ _} $camera]
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<label>
<input type="checkbox" name="camera-enabled"
$($isUsingCamera ? "checked" : "")
value="$camera"
onchange="cameraEnabledChange.call(this, event)">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)
</label>
<fieldset style="margin-left: 20px; margin-top: 10px">
<legend>Select resolution:</legend>
[join [lmap resolution $resolutions { subst {
<div class="mode">
<span class="resolution" data-camera="$camera"
data-resolution="width ${resolution(width)} height ${resolution(height)}"
onclick="cameraResolutionClicked.call(this, event)">
${resolution(width)}x${resolution(height)}
</span>
[join [lmap framerate $resolution(framerates) { subst {
<label>
<input type="radio" name="camera-framerate-$cameraId"
$([info exists usingOpts] &&
$resolution(width) == $usingOpts(width) &&
$resolution(height) == $usingOpts(height) &&
$framerate == $usingOpts(framerate) ?
"checked" : "")
data-camera="$camera"
value="width ${resolution(width)} height ${resolution(height)} framerate $framerate"
onchange="cameraFramerateChange.call(this, event)">
[format "%.3g" $framerate] Hz
</label>
} }] \n]
</div>
} }] \n]
</fieldset>
[if {$isUsingCamera} {
set iframeWidth 600
set cameraAreaHeight [expr {int(600.0 * $usingOpts(height) / $usingOpts(width))}]
set iframeHeight [expr {$cameraAreaHeight + 48}]
set existingCrops [dict getdef $usingOpts crops [list]]
subst {
<div class="camera-preview" data-camera="$camera"
style="position: relative; display: inline-block; margin-top: 10px; line-height: 0;">
<iframe src="/camera?camera=[string map {/ %2F} $camera]"
width="$iframeWidth" height="$iframeHeight"
style="border: 1px solid #999; display: block;"></iframe>
<div class="crop-overlay"
style="position: absolute; top: 1px; left: 1px;
width: ${iframeWidth}px; height: ${cameraAreaHeight}px;
pointer-events: none;">
<!-- [set i 0] -->
[join [lmap c $existingCrops {
set cx [dict get $c x]
set cy [dict get $c y]
set cw [dict get $c width]
set ch [dict get $c height]
set rx [expr {int($cx * $iframeWidth / $usingOpts(width))}]
set ry [expr {int($cy * $cameraAreaHeight / $usingOpts(height))}]
set rw [expr {int($cw * $iframeWidth / $usingOpts(width))}]
set rh [expr {int($ch * $cameraAreaHeight / $usingOpts(height))}]
set cropHtml [subst {
<div class="crop-box" data-index="$i" data-crop="$cx,$cy,$cw,$ch"
style="left: ${rx}px; top: ${ry}px;
width: ${rw}px; height: ${rh}px;">
<div class="crop-handle" data-corner="nw"></div>
<div class="crop-handle" data-corner="ne"></div>
<div class="crop-handle" data-corner="sw"></div>
<div class="crop-handle" data-corner="se"></div>
</div>
}]
incr i
set cropHtml
}] \n]
</div>
</div>
<div style="margin-top: 10px;">
<button data-camera="$camera"
onclick="createVirtualCroppedCamera.call(this, event)">
Create virtual cropped camera
</button>
</div>
} }]
</div>
}
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {__ref s1185:0 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {{fourcc {MJPG} description {Motion-JPEG} resolutions {{width 640 height 480 framerates {60.0 30.0}} {width 1600 height 896 framerates {60.0 30.0}} {width 1280 height 720 framerates {60.0 30.0}} {width 1024 height 768 framerates {60.0 30.0}} {width 1024 height 576 framerates {60.0 30.0}} {width 960 height 544 framerates {60.0 30.0}} {width 864 height 480 framerates {60.0 30.0}} {width 848 height 480 framerates {60.0 30.0}} {width 800 height 448 framerates {60.0 30.0}} {width 640 height 360 framerates {60.0 30.0}} {width 352 height 288 framerates {60.0 30.0}} {width 320 height 240 framerates {60.0 30.0}} {width 1920 height 1080 framerates {60.0 30.0}}}} {fourcc {YUYV} description {YUYV 4:2:2} resolutions {{width 640 height 480 framerates {30.0}} {width 1600 height 896 framerates {5.0}} {width 1280 height 720 framerates {10.0 5.0}} {width 1024 height 768 framerates {10.0 5.0}} {width 1024 height 576 framerates {10.0 5.0}} {width 960 height 544 framerates {10.0 5.0}} {width 864 height 480 framerates {10.0 5.0}} {width 848 height 480 framerates {10.0 5.0}} {width 800 height 448 framerates {10.0 5.0}} {width 640 height 360 framerates {30.0}} {width 352 height 288 framerates {30.0}} {width 320 height 240 framerates {30.0}} {width 1920 height 1080 framerates {5.0}}}}}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev (
[ m61901:1044 () ]
[ m61902:1054 (s49434:1249) ]
[ m61919:1053 () ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} {
set isUsingCamera $([llength $results] >= 1)
if {$isUsingCamera} {
set usingOpts [dict get [lindex $results 0] usingOpts]
}
set resolutions [list]
foreach format [dict get $opts formats] {
# For now, we only support MJPG. The more raw formats are
# rarely used by cameras at even medium resolutions and
# framerates, anyway, so it's only worth supporting MJPG.
if {$format(fourcc) eq "MJPG"} {
lappend resolutions {*}$format(resolutions)
}
}
set resolutions [lsort -command {apply {{a b} {
expr {[dict get $b width] - [dict get $a width]}
}}} $resolutions]
if {[llength $resolutions] == 0} {
# Cameras often have extra camera devices with no formats (or no
# MJPG, at least) for some reason. Not very useful for us.
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)<br>
(no supported formats)
</div>
}
} else {
set cameraId [string map {/ _} $camera]
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<label>
<input type="checkbox" name="camera-enabled"
$($isUsingCamera ? "checked" : "")
value="$camera"
onchange="cameraEnabledChange.call(this, event)">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)
</label>
<fieldset style="margin-left: 20px; margin-top: 10px">
<legend>Select resolution:</legend>
[join [lmap resolution $resolutions { subst {
<div class="mode">
<span class="resolution" data-camera="$camera"
data-resolution="width ${resolution(width)} height ${resolution(height)}"
onclick="cameraResolutionClicked.call(this, event)">
${resolution(width)}x${resolution(height)}
</span>
[join [lmap framerate $resolution(framerates) { subst {
<label>
<input type="radio" name="camera-framerate-$cameraId"
$([info exists usingOpts] &&
$resolution(width) == $usingOpts(width) &&
$resolution(height) == $usingOpts(height) &&
$framerate == $usingOpts(framerate) ?
"checked" : "")
data-camera="$camera"
value="width ${resolution(width)} height ${resolution(height)} framerate $framerate"
onchange="cameraFramerateChange.call(this, event)">
[format "%.3g" $framerate] Hz
</label>
} }] \n]
</div>
} }] \n]
</fieldset>
[if {$isUsingCamera} {
set iframeWidth 600
set cameraAreaHeight [expr {int(600.0 * $usingOpts(height) / $usingOpts(width))}]
set iframeHeight [expr {$cameraAreaHeight + 48}]
set existingCrops [dict getdef $usingOpts crops [list]]
subst {
<div class="camera-preview" data-camera="$camera"
style="position: relative; display: inline-block; margin-top: 10px; line-height: 0;">
<iframe src="/camera?camera=[string map {/ %2F} $camera]"
width="$iframeWidth" height="$iframeHeight"
style="border: 1px solid #999; display: block;"></iframe>
<div class="crop-overlay"
style="position: absolute; top: 1px; left: 1px;
width: ${iframeWidth}px; height: ${cameraAreaHeight}px;
pointer-events: none;">
<!-- [set i 0] -->
[join [lmap c $existingCrops {
set cx [dict get $c x]
set cy [dict get $c y]
set cw [dict get $c width]
set ch [dict get $c height]
set rx [expr {int($cx * $iframeWidth / $usingOpts(width))}]
set ry [expr {int($cy * $cameraAreaHeight / $usingOpts(height))}]
set rw [expr {int($cw * $iframeWidth / $usingOpts(width))}]
set rh [expr {int($ch * $cameraAreaHeight / $usingOpts(height))}]
set cropHtml [subst {
<div class="crop-box" data-index="$i" data-crop="$cx,$cy,$cw,$ch"
style="left: ${rx}px; top: ${ry}px;
width: ${rw}px; height: ${rh}px;">
<div class="crop-handle" data-corner="nw"></div>
<div class="crop-handle" data-corner="ne"></div>
<div class="crop-handle" data-corner="sw"></div>
<div class="crop-handle" data-corner="se"></div>
</div>
}]
incr i
set cropHtml
}] \n]
</div>
</div>
<div style="margin-top: 10px;">
<button data-camera="$camera"
onclick="createVirtualCroppedCamera.call(this, event)">
Create virtual cropped camera
</button>
</div>
} }]
</div>
}
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {{fourcc {MJPG} description {Motion-JPEG} resolutions {{width 640 height 480 framerates {60.0 30.0}} {width 1600 height 896 framerates {60.0 30.0}} {width 1280 height 720 framerates {60.0 30.0}} {width 1024 height 768 framerates {60.0 30.0}} {width 1024 height 576 framerates {60.0 30.0}} {width 960 height 544 framerates {60.0 30.0}} {width 864 height 480 framerates {60.0 30.0}} {width 848 height 480 framerates {60.0 30.0}} {width 800 height 448 framerates {60.0 30.0}} {width 640 height 360 framerates {60.0 30.0}} {width 352 height 288 framerates {60.0 30.0}} {width 320 height 240 framerates {60.0 30.0}} {width 1920 height 1080 framerates {60.0 30.0}}}} {fourcc {YUYV} description {YUYV 4:2:2} resolutions {{width 640 height 480 framerates {30.0}} {width 1600 height 896 framerates {5.0}} {width 1280 height 720 framerates {10.0 5.0}} {width 1024 height 768 framerates {10.0 5.0}} {width 1024 height 576 framerates {10.0 5.0}} {width 960 height 544 framerates {10.0 5.0}} {width 864 height 480 framerates {10.0 5.0}} {width 848 height 480 framerates {10.0 5.0}} {width 800 height 448 framerates {10.0 5.0}} {width 640 height 360 framerates {30.0}} {width 352 height 288 framerates {30.0}} {width 320 height 240 framerates {30.0}} {width 1920 height 1080 framerates {5.0}}}}}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev (
[ m61887:1054 () ]
[ m61898:1048 () ]
[ m61927:1054 (s49420:1239) ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} {
set isUsingCamera $([llength $results] >= 1)
if {$isUsingCamera} {
set usingOpts [dict get [lindex $results 0] usingOpts]
}
set resolutions [list]
foreach format [dict get $opts formats] {
# For now, we only support MJPG. The more raw formats are
# rarely used by cameras at even medium resolutions and
# framerates, anyway, so it's only worth supporting MJPG.
if {$format(fourcc) eq "MJPG"} {
lappend resolutions {*}$format(resolutions)
}
}
set resolutions [lsort -command {apply {{a b} {
expr {[dict get $b width] - [dict get $a width]}
}}} $resolutions]
if {[llength $resolutions] == 0} {
# Cameras often have extra camera devices with no formats (or no
# MJPG, at least) for some reason. Not very useful for us.
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)<br>
(no supported formats)
</div>
}
} else {
set cameraId [string map {/ _} $camera]
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<label>
<input type="checkbox" name="camera-enabled"
$($isUsingCamera ? "checked" : "")
value="$camera"
onchange="cameraEnabledChange.call(this, event)">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)
</label>
<fieldset style="margin-left: 20px; margin-top: 10px">
<legend>Select resolution:</legend>
[join [lmap resolution $resolutions { subst {
<div class="mode">
<span class="resolution" data-camera="$camera"
data-resolution="width ${resolution(width)} height ${resolution(height)}"
onclick="cameraResolutionClicked.call(this, event)">
${resolution(width)}x${resolution(height)}
</span>
[join [lmap framerate $resolution(framerates) { subst {
<label>
<input type="radio" name="camera-framerate-$cameraId"
$([info exists usingOpts] &&
$resolution(width) == $usingOpts(width) &&
$resolution(height) == $usingOpts(height) &&
$framerate == $usingOpts(framerate) ?
"checked" : "")
data-camera="$camera"
value="width ${resolution(width)} height ${resolution(height)} framerate $framerate"
onchange="cameraFramerateChange.call(this, event)">
[format "%.3g" $framerate] Hz
</label>
} }] \n]
</div>
} }] \n]
</fieldset>
[if {$isUsingCamera} {
set iframeWidth 600
set cameraAreaHeight [expr {int(600.0 * $usingOpts(height) / $usingOpts(width))}]
set iframeHeight [expr {$cameraAreaHeight + 48}]
set existingCrops [dict getdef $usingOpts crops [list]]
subst {
<div class="camera-preview" data-camera="$camera"
style="position: relative; display: inline-block; margin-top: 10px; line-height: 0;">
<iframe src="/camera?camera=[string map {/ %2F} $camera]"
width="$iframeWidth" height="$iframeHeight"
style="border: 1px solid #999; display: block;"></iframe>
<div class="crop-overlay"
style="position: absolute; top: 1px; left: 1px;
width: ${iframeWidth}px; height: ${cameraAreaHeight}px;
pointer-events: none;">
<!-- [set i 0] -->
[join [lmap c $existingCrops {
set cx [dict get $c x]
set cy [dict get $c y]
set cw [dict get $c width]
set ch [dict get $c height]
set rx [expr {int($cx * $iframeWidth / $usingOpts(width))}]
set ry [expr {int($cy * $cameraAreaHeight / $usingOpts(height))}]
set rw [expr {int($cw * $iframeWidth / $usingOpts(width))}]
set rh [expr {int($ch * $cameraAreaHeight / $usingOpts(height))}]
set cropHtml [subst {
<div class="crop-box" data-index="$i" data-crop="$cx,$cy,$cw,$ch"
style="left: ${rx}px; top: ${ry}px;
width: ${rw}px; height: ${rh}px;">
<div class="crop-handle" data-corner="nw"></div>
<div class="crop-handle" data-corner="ne"></div>
<div class="crop-handle" data-corner="sw"></div>
<div class="crop-handle" data-corner="se"></div>
</div>
}]
incr i
set cropHtml
}] \n]
</div>
</div>
<div style="margin-top: 10px;">
<button data-camera="$camera"
onclick="createVirtualCroppedCamera.call(this, event)">
Create virtual cropped camera
</button>
</div>
} }]
</div>
}
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {__ref s1186:0 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev (
[ m61881:975 (s49420:1239) ]
[ m61885:1055 () ]
[ m61894:1048 () ]
)when the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} {
set isUsingCamera $([llength $results] >= 1)
if {$isUsingCamera} {
set usingOpts [dict get [lindex $results 0] usingOpts]
}
set resolutions [list]
foreach format [dict get $opts formats] {
# For now, we only support MJPG. The more raw formats are
# rarely used by cameras at even medium resolutions and
# framerates, anyway, so it's only worth supporting MJPG.
if {$format(fourcc) eq "MJPG"} {
lappend resolutions {*}$format(resolutions)
}
}
set resolutions [lsort -command {apply {{a b} {
expr {[dict get $b width] - [dict get $a width]}
}}} $resolutions]
if {[llength $resolutions] == 0} {
# Cameras often have extra camera devices with no formats (or no
# MJPG, at least) for some reason. Not very useful for us.
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)<br>
(no supported formats)
</div>
}
} else {
set cameraId [string map {/ _} $camera]
subst {
<div style="margin: 10px 0; border: 1px solid #ccc; padding: 10px;">
<label>
<input type="checkbox" name="camera-enabled"
$($isUsingCamera ? "checked" : "")
value="$camera"
onchange="cameraEnabledChange.call(this, event)">
<strong>$camera</strong> (<code>[dict getdef $opts card ""]</code>)
</label>
<fieldset style="margin-left: 20px; margin-top: 10px">
<legend>Select resolution:</legend>
[join [lmap resolution $resolutions { subst {
<div class="mode">
<span class="resolution" data-camera="$camera"
data-resolution="width ${resolution(width)} height ${resolution(height)}"
onclick="cameraResolutionClicked.call(this, event)">
${resolution(width)}x${resolution(height)}
</span>
[join [lmap framerate $resolution(framerates) { subst {
<label>
<input type="radio" name="camera-framerate-$cameraId"
$([info exists usingOpts] &&
$resolution(width) == $usingOpts(width) &&
$resolution(height) == $usingOpts(height) &&
$framerate == $usingOpts(framerate) ?
"checked" : "")
data-camera="$camera"
value="width ${resolution(width)} height ${resolution(height)} framerate $framerate"
onchange="cameraFramerateChange.call(this, event)">
[format "%.3g" $framerate] Hz
</label>
} }] \n]
</div>
} }] \n]
</fieldset>
[if {$isUsingCamera} {
set iframeWidth 600
set cameraAreaHeight [expr {int(600.0 * $usingOpts(height) / $usingOpts(width))}]
set iframeHeight [expr {$cameraAreaHeight + 48}]
set existingCrops [dict getdef $usingOpts crops [list]]
subst {
<div class="camera-preview" data-camera="$camera"
style="position: relative; display: inline-block; margin-top: 10px; line-height: 0;">
<iframe src="/camera?camera=[string map {/ %2F} $camera]"
width="$iframeWidth" height="$iframeHeight"
style="border: 1px solid #999; display: block;"></iframe>
<div class="crop-overlay"
style="position: absolute; top: 1px; left: 1px;
width: ${iframeWidth}px; height: ${cameraAreaHeight}px;
pointer-events: none;">
<!-- [set i 0] -->
[join [lmap c $existingCrops {
set cx [dict get $c x]
set cy [dict get $c y]
set cw [dict get $c width]
set ch [dict get $c height]
set rx [expr {int($cx * $iframeWidth / $usingOpts(width))}]
set ry [expr {int($cy * $cameraAreaHeight / $usingOpts(height))}]
set rw [expr {int($cw * $iframeWidth / $usingOpts(width))}]
set rh [expr {int($ch * $cameraAreaHeight / $usingOpts(height))}]
set cropHtml [subst {
<div class="crop-box" data-index="$i" data-crop="$cx,$cy,$cw,$ch"
style="left: ${rx}px; top: ${ry}px;
width: ${rw}px; height: ${rh}px;">
<div class="crop-handle" data-corner="nw"></div>
<div class="crop-handle" data-corner="ne"></div>
<div class="crop-handle" data-corner="sw"></div>
<div class="crop-handle" data-corner="se"></div>
</div>
}]
incr i
set cropHtml
}] \n]
</div>
</div>
<div style="margin-top: 10px;">
<button data-camera="$camera"
onclick="createVirtualCroppedCamera.call(this, event)">
Create virtual cropped camera
</button>
</div>
} }]
</div>
}
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {}}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {/someone/ wishes folk-sva uses display /display/ with /...opts/} are (
[ m61930:1052 (s49462:1252) ]
[ m61935:1053 () ]
)when the collected results for {/someone/ wishes folk-sva uses display /display/ with /...opts/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {/someone/ wishes folk-sva uses display /display/ with /...opts/} {
subst {
<div style="margin: 5px 0;">
<label>
<input type="radio" name="calibration-display"
value="$display"
onchange="calibrationSelectionChange()">
$display
</label>
</div>
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} are /r (
[ m62004:1055 (s49548:1252) ]
[ m62007:1053 () ]
)when the collected results for {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} are /results/ {apply {{pattern body envStack} {
proc htmlEscape {s} { string map {& "&" < "<" > ">" "\"" """} $s }
upvar results results
lappend envStack {}
set htmls [list]
foreach result $results {
lset envStack end $result
lappend htmls [applyBlock $body $envStack]
}
Notify: the html for $pattern is [join $htmls \n]
}} {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} {
if {[dict exists $opts crops]} {
set htmls [list]
loop i [llength $opts(crops)] {
lappend htmls [emitCameraHtml [list $camera $i]]
}
join $htmls \n
} else {
emitCameraHtml $camera
}
} {{this builtin-programs/web/setup.folk} {} {} {QUERY {} 0 /setup 1 {}} {^emitCameraHtml {camera {
subst {
<div style="margin: 5px 0;">
<label>
<input type="checkbox" name="calibration-camera"
value="$camera"
onchange="calibrationSelectionChange()">
$camera
</label>
</div>
}
} {{} 1}}} {^HtmlWhen {args \n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n {builtin-programs/web/web.folk 106}}}}} with environment {}
when the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} a (
[ m61824:1035 (s49349:1239) ]
[ m61828:1042 () ]
)when the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} settle 0ms} {settleMs 0 settleNs 0}}
when the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00 (
[ m61888:969 (s49425:1240) ]
[ m61893:969 () ]
)when the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} settle 0ms} {settleMs 0 settleNs 0}}
when the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00 (
[ m61904:1055 (s49441:1250) ]
[ m61914:1055 () ]
)when the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} settle 0ms} {settleMs 0 settleNs 0}}
when the collected results for {/someone/ wishes 82 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m17866:1055 (s28217:1245) ]
[ m17871:1058 () ]
)when the collected results for {/someone/ wishes 82 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 82} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 82 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m17883:1058 (s28245:1248) ]
[ m17888:1058 () ]
)when the collected results for {/someone/ wishes 82 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 82} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 82 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m17880:1058 (s28242:1254) ]
[ m17886:1058 () ]
)when the collected results for {/someone/ wishes 82 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 82} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 82 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m17874:1058 (s28229:1254) ]
[ m17878:1057 () ]
)when the collected results for {/someone/ wishes 82 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 82} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 11 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m23226:1062 (s14529:1260) ]
[ m23229:1059 () ]
)when the collected results for {/someone/ wishes 11 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 11} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 11 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m23220:1061 (s14525:1259) ]
[ m23225:1061 () ]
)when the collected results for {/someone/ wishes 11 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 11} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 11 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m23209:1061 (s14513:1259) ]
[ m23218:1062 () ]
)when the collected results for {/someone/ wishes 11 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 11} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 11 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m23203:1061 (s14505:1248) ]
[ m23208:1061 () ]
)when the collected results for {/someone/ wishes 11 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 11} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ claims tag 54 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m23347:1062 (s14673:1259) ]
[ m23350:1059 (s14677:1260 s14678:1260 s53065:1170 s14680:1260) ]
)when the collected results for {/someone/ claims tag 54 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 54} {}}
when the collected results for {/someone/ wishes 54-frame-6 is labelled /text/ with /...options/} are (
[ m23384:1060 (s14728:1258) ]
[ m23386:1040 () ]
)when the collected results for {/someone/ wishes 54-frame-6 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-6 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-frame-5 is labelled /text/ with /...options/} are (
[ m23389:1040 (s14733:1258) ]
[ m23391:1062 () ]
)when the collected results for {/someone/ wishes 54-frame-5 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-5 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-frame-4 is labelled /text/ with /...options/} are (
[ m23399:1040 (s14744:1258) ]
[ m23401:1040 () ]
)when the collected results for {/someone/ wishes 54-frame-4 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-4 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-frame-3 is labelled /text/ with /...options/} are (
[ m23405:1062 (s14751:1260) ]
[ m23407:1062 () ]
)when the collected results for {/someone/ wishes 54-frame-3 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-3 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-frame-2 is labelled /text/ with /...options/} are (
[ m23410:1059 (s14756:1221) ]
[ m23413:1039 () ]
)when the collected results for {/someone/ wishes 54-frame-2 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-2 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-frame-1 is labelled /text/ with /...options/} are (
[ m23417:1040 (s14763:1259) ]
[ m23419:1062 () ]
)when the collected results for {/someone/ wishes 54-frame-1 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-frame-1 geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54-display is labelled /text/ with /...options/} are (
[ m23428:1061 (s14775:1222) ]
[ m23433:1062 () ]
)when the collected results for {/someone/ wishes 54-display is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54-display geom {width 0.1055 height 0.0695}} {}}
when the collected results for {/someone/ wishes 54 is labelled /text/ with /...options/} are /result (
[ m23482:1060 (s14836:1257) ]
[ m23990:1059 () ]
[ m24053:1067 () ]
[ m24834:706 () ]
[ m24862:1066 (s6145:1262) ]
)when the collected results for {/someone/ wishes 54 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 54 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when the collected results for {/someone/ wishes 54-frame-6 is titled /text/} are /results/ \n\ \ \ \ (
[ m23767:1062 (s15119:1260) ]
[ m23771:1060 () ]
)when the collected results for {/someone/ wishes 54-frame-6 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-6} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-6 is footnoted /text/} are /results/ \n\ \ (
[ m23763:1060 (s15114:1260) ]
[ m23766:1061 () ]
)when the collected results for {/someone/ wishes 54-frame-6 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-6} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-6 is right-margined /text/} are /results/ \ (
[ m23757:1062 (s15108:1260) ]
[ m23762:1061 () ]
)when the collected results for {/someone/ wishes 54-frame-6 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-6} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-6 is left-margined /text/} are /results/ \n (
[ m23749:1062 (s15102:1255) ]
[ m23754:1056 () ]
)when the collected results for {/someone/ wishes 54-frame-6 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-6} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 54 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m24271:1036 (s15712:1255) ]
[ m24273:1051 (s15717:1257) ]
)when the collected results for {/someone/ wishes 54 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m24288:1060 (s15732:1239) ]
[ m24293:1061 () ]
)when the collected results for {/someone/ wishes 54 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m24280:1057 (s15725:1237) ]
[ m24285:1062 () ]
)when the collected results for {/someone/ wishes 54 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m24274:1059 (s15718:1238) ]
[ m24278:1060 () ]
)when the collected results for {/someone/ wishes 54 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ claims tag 83 has geometry /geom/} are /results/ \n\ \ \ \ (
[ m47702:1058 (s64450:987) ]
[ m47705:1057 () ]
[ m47715:1056 (s64469:1262 s64472:1262 s59987:1247 s64481:1262) ]
)when the collected results for {/someone/ claims tag 83 has geometry /geom/} are /results/ \n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 83} {}}
when the collected results for {/any/ wishes program 83 does not run} are /__results/ {if {[llength $ (
[ m47709:1058 (s64464:1258) ]
[ m47718:1064 (s64473:1262 s64479:1262) ]
)when the collected results for {/any/ wishes program 83 does not run} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ When\ /nobody/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$_this\ is\ replaced\ with\ /...replacedOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ } with environment {{_this 83 programCode {Claim $this is a viewport
}} {}}
when the collected results for {/any/ wishes program 83 is replaced with /...anything/} are /__result (
[ m47772:1063 (s64537:1262) ]
[ m47776:1061 () ]
)when the collected results for {/any/ wishes program 83 is replaced with /...anything/} are /__results/ {if {[llength $__results] == 0} \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \$programCode\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ } with environment {{_this 83 programCode {Claim $this is a viewport
}} {} {__results {}} {}}
when the collected results for {/someone/ wishes 83 is labelled /text/ with /...options/} are /result (
[ m47782:1063 (s64546:1261) ]
[ m47787:1061 () ]
)when the collected results for {/someone/ wishes 83 is labelled /text/ with /...options/} are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
} with environment {{this builtin-programs/decorations/label.folk} {} {} {thing 83 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}} {}}
when the collected results for {/someone/ wishes 54-frame-5 is titled /text/} are /results/ \n\ \ \ \ (
[ m60537:1064 (s15428:1257) ]
[ m60540:1056 () ]
)when the collected results for {/someone/ wishes 54-frame-5 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-5} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-5 is footnoted /text/} are /results/ \n\ \ (
[ m60531:1034 (s15421:1259) ]
[ m60536:1056 () ]
)when the collected results for {/someone/ wishes 54-frame-5 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-5} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-5 is right-margined /text/} are /results/ \ (
[ m60527:1043 (s15417:1261) ]
[ m60530:1042 () ]
)when the collected results for {/someone/ wishes 54-frame-5 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-5} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-5 is left-margined /text/} are /results/ \n (
[ m60522:1044 (s15412:1259) ]
[ m60526:1040 () ]
)when the collected results for {/someone/ wishes 54-frame-5 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-5} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 54-frame-1 is titled /text/} are /results/ \n\ \ \ \ (
[ m29777:1057 (s54503:1255) ]
[ m29783:1064 () ]
)when the collected results for {/someone/ wishes 54-frame-1 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-1} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-1 is footnoted /text/} are /results/ \n\ \ (
[ m29769:1060 (s54495:1257) ]
[ m29774:1060 () ]
)when the collected results for {/someone/ wishes 54-frame-1 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-1} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-1 is right-margined /text/} are /results/ \ (
[ m29764:1057 (s54486:1244) ]
[ m29768:1057 () ]
)when the collected results for {/someone/ wishes 54-frame-1 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-1} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-1 is left-margined /text/} are /results/ \n (
[ m29757:1065 (s54479:1244) ]
[ m29763:1056 () ]
)when the collected results for {/someone/ wishes 54-frame-1 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-1} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 54-frame-4 is titled /text/} are /results/ \n\ \ \ \ (
[ m49812:1065 (s13729:1264) ]
[ m49816:1065 () ]
)when the collected results for {/someone/ wishes 54-frame-4 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-4} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-4 is footnoted /text/} are /results/ \n\ \ (
[ m49800:1061 (s13719:1254) ]
[ m49806:1065 () ]
)when the collected results for {/someone/ wishes 54-frame-4 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-4} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-4 is right-margined /text/} are /results/ \ (
[ m49796:1060 (s13713:1261) ]
[ m49799:1064 () ]
)when the collected results for {/someone/ wishes 54-frame-4 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-4} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-4 is left-margined /text/} are /results/ \n (
[ m49790:1064 (s13706:1262) ]
[ m49793:1065 () ]
)when the collected results for {/someone/ wishes 54-frame-4 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-4} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 54-frame-2 is titled /text/} are /results/ \n\ \ \ \ (
[ m45038:1066 (s19107:1264) ]
[ m45042:1066 () ]
)when the collected results for {/someone/ wishes 54-frame-2 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-2} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-2 is footnoted /text/} are /results/ \n\ \ (
[ m45033:1063 (s19101:1265) ]
[ m45035:1065 () ]
)when the collected results for {/someone/ wishes 54-frame-2 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-2} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-2 is right-margined /text/} are /results/ \ (
[ m45028:1062 (s19097:1265) ]
[ m45032:1066 () ]
)when the collected results for {/someone/ wishes 54-frame-2 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-2} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-2 is left-margined /text/} are /results/ \n (
[ m45022:1065 (s19089:1265) ]
[ m45027:1065 () ]
)when the collected results for {/someone/ wishes 54-frame-2 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-2} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 54-frame-3 is titled /text/} are /results/ \n\ \ \ \ ()when the collected results for {/someone/ wishes 54-frame-3 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-3} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 54-frame-3 is footnoted /text/} are /results/ \n\ \ ()when the collected results for {/someone/ wishes 54-frame-3 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-3} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 54-frame-3 is right-margined /text/} are /results/ \ ()when the collected results for {/someone/ wishes 54-frame-3 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-3} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 54-frame-3 is left-margined /text/} are /results/ \n ()when the collected results for {/someone/ wishes 54-frame-3 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54-frame-3} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the collected results for {/someone/ wishes 83 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ (
[ m2145:1066 (s44072:1265) ]
[ m2153:1065 (s44089:1265) ]
)when the collected results for {/someone/ wishes 83 is titled /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 83} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top}}
when the collected results for {/someone/ wishes 83 is footnoted /text/} are /results/ \n\ \ \ \ \ \ (
[ m2133:1061 (s44061:1264) ]
[ m2140:1061 () ]
)when the collected results for {/someone/ wishes 83 is footnoted /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 83} {label footnoted ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor top edge bottom}}
when the collected results for {/someone/ wishes 83 is right-margined /text/} are /results/ \n\ \ \ \ (
[ m2123:1061 (s44051:1265) ]
[ m2130:1062 () ]
)when the collected results for {/someone/ wishes 83 is right-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 83} {label right-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor left edge right}}
when the collected results for {/someone/ wishes 83 is left-margined /text/} are /results/ \n\ \ \ \ (
[ m2111:1067 (s44040:1240) ]
[ m2119:1063 () ]
)when the collected results for {/someone/ wishes 83 is left-margined /text/} are /results/ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 83} {label left-margined ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor right edge left}}
when the internal time is /t/ {
$collectLib RunScheduledRecollects!
} with environment {{this bui (
[ m25043:1057 () ]
[ m25117:1064 () ]
[ m25191:1067 () ]
[ m25223:1058 () ]
[ m25300:1047 () ]
[ m25320:1065 () ]
[ m25360:1067 () ]
[ m25493:1066 () ]
)when the internal time is /t/ {
$collectLib RunScheduledRecollects!
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>}}
when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadCha (
[ m1391:0 (s2252:0) ]
)when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadChange/ & display /proj/ has width /projWidth/ height /projHeight/ & display /proj/ has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/mask-tags.folk} {} {}}
when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadCha (
[ m1392:0 (s2254:0) ]
)when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadChange/ & display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n} with environment {{this builtin-programs/points-at.folk} {} {}}
when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadCha (
[ m1395:0 (s2257:0) ]
)when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadChange/ & display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/title.folk} {} {}}
when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadCha (
[ m1397:0 (s2261:0) ]
)when the quad library is /quadLib/ {When the pose library is /poseLib/ & the quad changer is /quadChange/ & /someone/ wishes /p/ has camera slice & camera /cam/ has intrinsics /cameraIntrinsics/ & camera /cam/ has frame /frame/ at timestamp /timestamp/ & /p/ has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when the quad library is /quadLib/ {When the collected results for {the changer from space /sourceSpa (
[ m1398:0 (s2262:0) ]
)when the quad library is /quadLib/ {When the collected results for {the changer from space /sourceSpace/ to space /targetSpace/ is /changer/} are /results/ \n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when the quad library is /quadLib/ {When 54 has quad /q/ {
set displayQuad [$quadLib scale $q 50% (
[ m6529:989 (s53049:1174) ]
)when the quad library is /quadLib/ {When 54 has quad /q/ {
set displayQuad [$quadLib scale $q 50%]
set displayQuad [$quadLib move $displayQuad up 60% right 160%]
Claim -keep 10ms $this-display has quad $displayQuad
Wish -keep 10ms $this-display is outlined white
}} with environment {{this 54} {} {COLS 3}}
when the quad library is /quadLib/ {When 54 has quad /q/ & 54-display has resolved geometry /geom/ & (
[ m6525:944 (s53047:1174) ]
)when the quad library is /quadLib/ {When 54 has quad /q/ & 54-display has resolved geometry /geom/ & the animation toy's fps is /FPS/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3}}
when the quad library is /quadLib/ {When the quad changer is /quadChange/ & 54 has resolved geometry (
[ m6540:943 (s53066:1173) ]
)when the quad library is /quadLib/ {When the quad changer is /quadChange/ & 54 has resolved geometry /geom/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {}}
when the quad changer is /quadChange/ {When display /proj/ has width /projWidth/ height /projHeight/ (
[ m1406:0 (s2269:0) ]
)when the quad changer is /quadChange/ {When display /proj/ has width /projWidth/ height /projHeight/ & display /proj/ has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {}}
when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHe (
[ m1407:0 (s2271:0) ]
)when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n} with environment {{this builtin-programs/points-at.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {}}
when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHe (
[ m1409:0 (s2272:0) ]
)when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /tag/ has canvas /writableTextureId/ with /...wiOptions/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHe (
[ m1410:0 (s2273:0) ]
)when the quad changer is /quadChange/ {When display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {}}
when the quad changer is /quadChange/ {When /someone/ wishes /p/ has camera slice & camera /cam/ has (
[ m1408:0 (s2270:0) ]
)when the quad changer is /quadChange/ {When /someone/ wishes /p/ has camera slice & camera /cam/ has intrinsics /cameraIntrinsics/ & camera /cam/ has frame /frame/ at timestamp /timestamp/ & /p/ has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {}}
when the quad changer is /quadChange/ {When 54 has resolved geometry /geom/ & the animation toy's fra (
[ m6543:990 (s53070:1171) ]
)when the quad changer is /quadChange/ {When 54 has resolved geometry /geom/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the image library is /imageLib/ {When the jpeg library is /jpegLib/ \n\nset\ camc\ \[C\]\n\$camc (
[ m899:0 (s1398:0) ]
)when the image library is /imageLib/ {When the jpeg library is /jpegLib/ \n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n} with environment {{this builtin-programs/camera/usb.folk} {} {}}
when the image library is /imageLib/ {When libapriltag has been built with config /configCcWithLibapr (
[ m900:0 (s1396:0) ]
)when the image library is /imageLib/ {When libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n} with environment {{this builtin-programs/laser.folk} {} {}}
when the image library is /imageLib/ {When the image loader is /loadImage/ & /anyone/ wishes /p/ draw (
[ m901:0 (s1399:0) ]
)when the image library is /imageLib/ {When the image loader is /loadImage/ & /anyone/ wishes /p/ draws sprite /path/ with /...options/ {
set frames [dict get $options frames]
set columns [dict get $options columns]
set fps [dict getdef $options fps 60]
fn loadImage
set im [loadImage $path]
set sheetWidth [$imageLib Image_width $im]
set sheetHeight [$imageLib Image_height $im]
set spriteWidth [/ $sheetWidth $columns]
set rows [/ $frames $columns]
set spriteHeight [/ $sheetHeight $rows]
When -atomicallyWithKey [list sprite $p $path] the clock time is /t/ {
set frameNumber [expr {round ($t * $fps) % $frames}]
set x [expr {($frameNumber % $columns) * $spriteWidth}]
set y [expr {($frameNumber % $rows) * $spriteHeight}]
set subimage [$imageLib slice $im $x $y $spriteWidth $spriteHeight]
Wish $p displays image $subimage with {*}$options
}
}} with environment {{this builtin-programs/sprites.folk} {} {}}
when the image library is /imageLib/ \n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\ (
[ m903:0 (s1431:0 s1432:0 s1798:0 s1801:0 s1803:0) ]
)when the image library is /imageLib/ \n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n with environment {{this builtin-programs/apriltags.folk} {} {}}
when the image library is /imageLib/ {When the quad library is /quadLib/ & the pose library is /poseL (
[ m905:0 (s1401:0) ]
)when the image library is /imageLib/ {When the quad library is /quadLib/ & the pose library is /poseLib/ & the quad changer is /quadChange/ & /someone/ wishes /p/ has camera slice & camera /cam/ has intrinsics /cameraIntrinsics/ & camera /cam/ has frame /frame/ at timestamp /timestamp/ & /p/ has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {}}
when the image library is /imageLib/ {When the print library is /printLib/ & /p/ has canvas /writable (
[ m906:0 (s1402:0) ]
)when the image library is /imageLib/ {When the print library is /printLib/ & /p/ has canvas /writableTexture/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ & /someone/ wishes to draw an AprilTag onto /p/ with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {}}
when the image library is /imageLib/ {When /someone/ wishes to draw an image onto /p/ with /...option (
[ m907:0 (s1403:0) ]
)when the image library is /imageLib/ {When /someone/ wishes to draw an image onto /p/ with /...options/ & /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/image.folk} {} {}}
when the image library is /imageLib/ {When the image loader is /loadImage/ & /someone/ wishes /p/ dis (
[ m908:0 (s1404:0) ]
)when the image library is /imageLib/ {When the image loader is /loadImage/ & /someone/ wishes /p/ displays image /impath/ with /...options/ & /p/ has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n} with environment {{this builtin-programs/draw/image.folk} {} {}}
when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./ven (
[ m910:0 (s1656:0) ]
)when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
} with environment {{this builtin-programs/image/gif-lib.folk} {} {}}
when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc (
[ m914:0 (s1771:0) ]
)when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
} with environment {{this builtin-programs/image/jpeg-lib.folk} {} {}}
when the image library is /imageLib/ \n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <ma (
[ m934:0 (s2326:0 s2327:0 s2328:0 s2329:0 s2330:0) ]
)when the image library is /imageLib/ \n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/draw/text.folk} {} {}}
when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc includ (
[ m935:0 (s1732:0) ]
)when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
} with environment {{this builtin-programs/image/png-lib.folk} {} {}}
when the image library is /imageLib/ {When /someone/ wishes folk-sva uses camera /cameraPath/ with /. (
[ m941:0 (s1638:0) ]
)when the image library is /imageLib/ {When /someone/ wishes folk-sva uses camera /cameraPath/ with /...options/ \n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n} with environment {{this builtin-programs/camera/rpi.folk} {} {makeCamera {
set cpp [C++]
$cpp extend $imageLib
$cpp include <iostream>
$cpp include <iomanip>
$cpp include <mutex>
$cpp include <condition_variable>
$cpp include <queue>
$cpp include <sys/mman.h>
$cpp include <libcamera/libcamera.h>
# osnr: HACK: just throwing any possible path in.
$cpp cflags -I/usr/local/include/libcamera -I/usr/include/libcamera
$cpp endcflags -lcamera
$cpp code {
using namespace libcamera;
std::unique_ptr<CameraManager> cm;
std::shared_ptr<Camera> camera;
std::unique_ptr<CameraConfiguration> config;
FrameBufferAllocator *allocator;
// This vector always owns all the request objects.
std::vector<std::unique_ptr<Request>> requests;
std::mutex completedRequestsMutex;
std::queue<Request *> completedRequests;
std::condition_variable completedRequestsCv;
uint32_t frameWidth;
uint32_t frameHeight;
uint32_t frameBytesPerRow;
static void requestComplete(Request *request);
}
$cpp proc cameraOpen {char* id int width int height} void {
cm = std::make_unique<CameraManager>();
cm->start();
std::cout << "camera/rpi: cameras:" << std::endl;
for (auto const &camera : cm->cameras()) {
std::cout << " - " << camera->id() << std::endl;
}
camera = cm->get(id);
FOLK_ENSURE(camera != nullptr);
camera->acquire();
config = camera->generateConfiguration({ StreamRole::Viewfinder });
StreamConfiguration &streamConfig = config->at(0);
streamConfig.size = Size(width, height);
streamConfig.pixelFormat = PixelFormat::fromString("YUV420");
config->validate();
frameWidth = streamConfig.size.width;
frameHeight = streamConfig.size.height;
frameBytesPerRow = streamConfig.stride;
std::cout << "frameWidth: " << frameWidth << " frameHeight: " << frameHeight << std::endl;
camera->configure(config.get());
allocator = new FrameBufferAllocator(camera);
for (StreamConfiguration &cfg : *config) {
int ret = allocator->allocate(cfg.stream());
if (ret < 0) {
FOLK_ERROR("Can't allocate buffers");
}
size_t allocated = allocator->buffers(cfg.stream()).size();
std::cout << "camera/rpi: Allocated " << allocated << " buffers for stream" << std::endl;
// for (PixelFormat &format : cfg.formats().pixelformats()) {
// std::cout << "camera/rpi: Stream supports format " << format << std::endl;
// for (Size &size : cfg.formats().sizes(format)) {
// std::cout << " -> supports size " << size << std::endl;
// }
// }
}
Stream *stream = streamConfig.stream();
assert(streamConfig.pixelFormat.toString() == "YUV420");
const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator->buffers(stream);
for (unsigned int i = 0; i < buffers.size(); ++i) {
std::unique_ptr<Request> request = camera->createRequest();
if (!request) {
FOLK_ERROR("camera/rpi: Can't create request");
}
const std::unique_ptr<FrameBuffer> &buffer = buffers[i];
int ret = request->addBuffer(stream, buffer.get());
if (ret < 0) {
FOLK_ERROR("camera/rpi: Can't set buffer for request");
}
ControlList &controls = request->controls();
controls.set(controls::AeEnable, false);
controls.set(controls::ExposureTime, 35000);
controls.set(controls::AfMode, controls::AfModeManual);
// Focus 30cm away (0.3m -> 1/0.3 = 3.3).
controls.set(controls::LensPosition, 1.6);
requests.push_back(std::move(request));
}
camera->requestCompleted.connect(requestComplete);
camera->start();
for (std::unique_ptr<Request> &request : requests) {
camera->queueRequest(request.get());
}
}
$cpp code {
static void requestComplete(Request *request) {
if (request->status() == Request::RequestCancelled) {
return;
}
completedRequestsMutex.lock();
completedRequests.push(request);
completedRequestsMutex.unlock();
completedRequestsCv.notify_one();
}
static void processRequestAndCopyFrame(Request *request, Image im) {
const Request::BufferMap &buffers = request->buffers();
assert(buffers.size() == 1);
for (auto bufferPair : buffers) {
// (Unused) Stream *stream = bufferPair.first;
FrameBuffer *buffer = bufferPair.second;
const FrameMetadata &metadata = buffer->metadata();
assert(metadata.planes().size() == 3);
assert(buffer->planes().size() == 3);
auto &plane = buffer->planes()[0];
int fd = plane.fd.get();
void *addr = mmap64(NULL, plane.length, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) {
FOLK_ERROR("camera/rpi: MAP_FAILED");
}
void *planeData = (uint8_t *)addr + plane.offset;
memcpy(im.data, planeData, frameHeight * frameBytesPerRow);
munmap(addr, plane.length);
}
}
}
$cpp proc newImage {} Image {
uint32_t width = frameWidth;
uint32_t height = frameHeight;
int components = 1;
uint8_t *data = (uint8_t *) malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data
};
}
$cpp proc freeImage {Image image} void {
free(image.data);
}
$cpp proc grayFrame {} Image {
Request *latestRequest = nullptr;
// We want to drain the queue of completed requests.
std::unique_lock lk(completedRequestsMutex);
completedRequestsCv.wait(lk, []{
return !completedRequests.empty();
});
while (!completedRequests.empty()) {
if (latestRequest != nullptr) {
// We're skipping this request, because we have a
// newer one in the queue. Requeue it.
latestRequest->reuse(Request::ReuseBuffers);
camera->queueRequest(latestRequest);
}
latestRequest = completedRequests.front();
completedRequests.pop();
}
lk.unlock();
if (latestRequest == nullptr) {
FOLK_ERROR("No new frame yet");
}
Image im = newImage();
processRequestAndCopyFrame(latestRequest, im);
/* Re-queue the Request to the camera. */
latestRequest->reuse(Request::ReuseBuffers);
camera->queueRequest(latestRequest);
return im;
}
$cpp compile
}}}
when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I.
(
[ m902:0 (s1635:0) ]
)when the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I.
$cc include "vendor/CContour.c"
# Binarizes the first channel of `im` at `threshold` and returns
# the contours as a Tcl list. Each contour is itself a Tcl list of
# {x y} pairs. If epsilon > 0, each contour is simplified with
# Ramer-Douglas-Peucker.
#
# Contours are scaled by `scaleX` and `scaleY` so that they can be
# returned in real-world meters (instead of image-pixel space).
#
# Discards any contours that are not at least minLength long
# (unless minLength is very small).
$cc proc findImageContours {Image im int threshold double epsilon
double scaleX double scaleY
double minLength} Jim_Obj* {
int w = (int)im.width;
int h = (int)im.height;
if (w < 3 || h < 3) return Jim_NewListObj(interp, NULL, 0);
int *F = malloc(sizeof(int) * (size_t)w * (size_t)h);
for (int y = 0; y < h; y++) {
uint8_t *row = im.data + (size_t)y * im.bytesPerRow;
int *Frow = F + (size_t)y * w;
for (int x = 0; x < w; x++) {
Frow[x] = (row[x * im.components] > threshold) ? 1 : 0;
}
}
Contour *contours = findContours(F, w, h);
free(F);
Jim_Obj *outer = Jim_NewListObj(interp, NULL, 0);
for (ptrdiff_t c = 0; c < arrlen(contours); c++) {
Point *pts = (epsilon > 0)
? approxPolyDP(contours[c].points, (float)epsilon)
: contours[c].points;
ptrdiff_t n = arrlen(pts);
if (minLength > 0.0001) {
double total = 0;
for (ptrdiff_t k = 1; k < n; k++) {
double dx = (pts[k].x - pts[k-1].x) * scaleX;
double dy = (pts[k].y - pts[k-1].y) * scaleY;
total += sqrt(dx*dx + dy*dy);
}
if (total < minLength) {
if (epsilon > 0) arrfree(pts);
continue;
}
}
// %g prints up to ~13 chars per double; round up to give headroom.
size_t cap = (size_t)n * 40 + 1;
char *buf = malloc(cap);
size_t off = 0;
for (ptrdiff_t k = 0; k < n; k++) {
off += snprintf(buf + off, cap - off,
k == 0 ? "{%g %g}" : " {%g %g}",
pts[k].x * scaleX, pts[k].y * scaleY);
}
// Jim_NewStringObjNoAlloc takes ownership of buf.
Jim_ListAppendElement(interp, outer,
Jim_NewStringObjNoAlloc(interp, buf, (int)off));
if (epsilon > 0) arrfree(pts);
}
freeContours(contours);
return outer;
}
set contourLib [$cc compile]
Claim the contour library is $contourLib
} with environment {{this builtin-programs/recognition/contours.folk} {} {}}
when the image library is /imageLib/ {When the program save directory is /saveDir/ \nfn\ configCcWith (
[ m937:0 (s1630:0) ]
)when the image library is /imageLib/ {When the program save directory is /saveDir/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n} with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {}}
when the image library is /imageLib/ {When -serially camera /camera/ has gray frame /frame/ at timest (
[ m1030:0 (s1809:0) ]
)when the image library is /imageLib/ {When -serially camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n} with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13} {__results {}} {}}
when the image library is /imageLib/ {When the program save directory is /saveDir/ {
fn printPro (
[ m1042:0 (s1823:0) ]
)when the image library is /imageLib/ {When the program save directory is /saveDir/ {
fn printProgram {printer id code} {
if {[file exists "$saveDir/$id.folk"]} {
error "Program $id already exists on disk. Aborting print."
}
writeFolkFile $id $code
writeMetaFile $printer $id
Expect! $printer is at /address/
set printerSocket [socket stream ${address}:9100]
fconfigure $printerSocket -translation binary -buffering none
set template {
[init]
[tag $id]
[feed 1]
$id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])
[feed 2]
$code
[feed 3]
[cut]
}
puts -nonewline $printerSocket [render $template]
close $printerSocket
}
fn render {template} {
set trimmed [lmap line [split $template "\n"] { string trim $line }]
set singleLine [join $trimmed ""]
return [uplevel [list subst $singleLine]]
}
fn writeFolkFile {id code} {
set folkFile [open "$saveDir/$id.folk" w]
puts $folkFile $code
close $folkFile
}
fn writeMetaFile {printer id} {
Expect! $printer has tag geometry /geometry/
set metaFile [open "$saveDir/$id.meta.folk" w]
puts $metaFile [subst {Claim tag \$this has geometry {$geometry}}]
close $metaFile
}
fn cut {} {
return "\x1dV\x0"
}
fn feed n {
return [format "\x1b\x64%c" $n]
}
fn init {} {
return "\x1b\x40"
}
fn raw number {
return [format "%c" $number]
}
fn scaledAprilTag {id scale} {
set tagImage [$printLib tagImageForId $id]
set tagBits [list]
for {set y 0} {$y < 10} {incr y} {
for {set i 0 } {$i < $scale} {incr i} {
for {set x 0} {$x < 10} {incr x} {
set j [expr {$y * [$imageLib Image_bytesPerRow $tagImage] + $x}]
set bit [expr {[$imageLib Image_data $tagImage $j] != 255}]
lappend tagBits {*}[lrepeat $scale $bit]
}
}
}
return $tagBits
}
# scale must be divisible by 4 so width will be divisible by 8
fn tag {id {scale 12}} {
set tagBits [scaledAprilTag $id $scale]
set width [expr {10 * $scale}]
set xL [expr {$width / 8}] ;# width in bytes (low byte)
set yL [expr {$width % 256}] ;# height in lines (low byte)
set yH [expr {$width / 256}] ;# height in lines (high byte)
return "\x1dv0\x03[raw $xL]\x00[raw $yL][raw $yH][binary format B* [join $tagBits ""]]"
}
Subscribe: print program /id/ on receipt printer /printer/ with code /code/ {
printProgram $printer $id $code
}
}} with environment {{this builtin-programs/esc-pos.folk} {} {} {printLib <C:cfileDzXJHE>} {}}
when the image library is /imageLib/ {When the GPU draw library is /drawLib/ & the GPU VMA DLL is /vm (
[ m2254:0 (s3345:0) ]
)when the image library is /imageLib/ {When the GPU draw library is /drawLib/ & the GPU VMA DLL is /vmaDll/ & the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cflags -I./vendor
$cc endcflags $vmaDll
$cc include <png.h>
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
#include "vk_mem_alloc.h"
VmaAllocator vmaGetAllocator();
VkDevice device;
}
# HACK: to make gpuLib extend properly
$cc typedef {struct PushConstantsEncoder} PushConstantsEncoder
$cc typedef {struct Pipeline} Pipeline
$cc typedef {struct VmaAllocation_T*} VmaAllocation
$cc argtype VmaAllocation {
VmaAllocation $argname;
sscanf(Jim_String($obj), "(VmaAllocation) %p", &$argname);
}
$cc rtype VmaAllocation {
char buf[100];
snprintf(buf, 100, "(VmaAllocation) %p", $rvalue);
$robj = Jim_NewStringObj(interp, buf, -1);
}
$cc extend $gpuLib
$cc extend $imageLib
$cc extend $gpuTextureLib
$cc proc texturesLibInit {} void {
volkInitialize();
volkLoadInstanceOnly(*instance_ptr());
device = *device_ptr();
volkLoadDevice(device);
}
$cc proc copyTextureFromGpu {GpuTextureHandle han} Image {
GpuTextureBlock* block = getGpuTexture(han);
if (!block->alive) {
return (Image){0};
}
Image im = {
.width = block->width,
.height = block->height,
.components = 4, // HACK: hard-coded for now
.bytesPerRow = block->width * 4,
.data = malloc(block->width * block->height * 4)
};
VkBuffer stagingBuffer;
VmaAllocation stagingBufferAllocation;
size_t stagingBufferSize = block->width * block->height * 4;
createBuffer(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&stagingBuffer, &stagingBufferAllocation);
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = block->textureImage,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT
};
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
// Copy image to buffer
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {block->width, block->height, 1}
};
vkCmdCopyImageToBuffer(
commandBuffer,
block->textureImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
stagingBuffer,
1,
®ion
);
// Transition image layout back
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkFence fence = getFence();
endSingleTimeCommands(commandBuffer, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Copy staging buffer back to CPU
void* data;
vmaMapMemory(vmaGetAllocator(), stagingBufferAllocation, &data);
memcpy(im.data, data, stagingBufferSize);
vmaUnmapMemory(vmaGetAllocator(), stagingBufferAllocation);
// Cleanup staging buffer
vmaDestroyBuffer(vmaGetAllocator(), stagingBuffer, stagingBufferAllocation);
return im;
}
$cc code {
struct WriteState {
uint8_t* buffer;
size_t* size;
};
void pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
struct WriteState* state = (struct WriteState*)png_get_io_ptr(png_ptr);
memcpy(state->buffer + *state->size, data, length);
*state->size += length;
}
}
$cc proc imageToPngBuffer {Image im size_t* outSize} uint8_t* {
size_t bufferSize = im.width * im.height * im.components * 2; // max size estimate
uint8_t* buffer = malloc(bufferSize);
*outSize = 0;
png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_w) {
free(buffer);
return NULL;
}
png_infop info_w = png_create_info_struct(png_w);
if (!info_w) {
png_destroy_write_struct(&png_w, NULL);
free(buffer);
return NULL;
}
struct WriteState state = {
.buffer = buffer,
.size = outSize
};
png_set_write_fn(png_w, &state, pngWriteCallback, NULL);
if (im.components == 4) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else if (im.components == 3) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_destroy_write_struct(&png_w, &info_w);
free(buffer);
return NULL;
}
png_bytep* row_pointers = malloc(sizeof(png_bytep) * im.height);
for (int y = 0; y < im.height; y++) {
row_pointers[y] = im.data + y * im.bytesPerRow;
}
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
png_destroy_write_struct(&png_w, &info_w);
*outSize = bufferSize;
return buffer;
}
$cc proc copyAllTexturesFromGpu {} Jim_Obj* {
Jim_Obj* ret = Jim_NewListObj(interp, NULL, 0);
for (int i = 0; i < getMaxTextures(); i++) {
if (getGpuTexture(i)->alive) {
Image im = copyTextureFromGpu(i);
size_t pngSize;
uint8_t* pngData = imageToPngBuffer(im, &pngSize);
Jim_ListAppendElement(interp, ret, Jim_ObjPrintf("Image %d (%d x %d)", i, im.width, im.height));
Jim_ListAppendElement(interp, ret, Jim_NewStringObj(interp, (char*)pngData, pngSize));
free(pngData);
free(im.data);
}
}
return ret;
}
set texturesLib [$cc compile]
$texturesLib texturesLibInit
Wish the web server handles route {/textures} with handler {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
}
}} with environment {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {}}
when the image library is /imageLib/ {When the GPU texture library is /gpuTextureLib/ \n\nfn\ defineV (
[ m2255:0 (s3350:0) ]
)when the image library is /imageLib/ {When the GPU texture library is /gpuTextureLib/ \n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n} with environment {{this builtin-programs/gpu/pipelines.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuLib <C:cfileog6zwp>} {}}
when the image library is /imageLib/ {When the GPU pipeline library is /pipelineLib/ & the GPU textur (
[ m2256:0 (s3351:0) ]
)when the image library is /imageLib/ {When the GPU pipeline library is /pipelineLib/ & the GPU texture library is /gpuTextureLib/ \n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {}}
when the image library is /imageLib/ \n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cfla (
[ m13901:0 (s23863:0 s23866:0) ]
)when the image library is /imageLib/ \n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n with environment {{this builtin-programs/gpu/textures.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuLib <C:cfileog6zwp>} {} {vmaDll /tmp/cfilequ8HAs.so} {}}
when the image loader is /loadImage/ {When /anyone/ wishes /p/ draws sprite /path/ with /...options/ (
[ m904:0 () ]
[ m950:0 () ]
[ m971:0 () ]
[ m1005:0 (s1776:0) ]
)when the image loader is /loadImage/ {When /anyone/ wishes /p/ draws sprite /path/ with /...options/ {
set frames [dict get $options frames]
set columns [dict get $options columns]
set fps [dict getdef $options fps 60]
fn loadImage
set im [loadImage $path]
set sheetWidth [$imageLib Image_width $im]
set sheetHeight [$imageLib Image_height $im]
set spriteWidth [/ $sheetWidth $columns]
set rows [/ $frames $columns]
set spriteHeight [/ $sheetHeight $rows]
When -atomicallyWithKey [list sprite $p $path] the clock time is /t/ {
set frameNumber [expr {round ($t * $fps) % $frames}]
set x [expr {($frameNumber % $columns) * $spriteWidth}]
set y [expr {($frameNumber % $rows) * $spriteHeight}]
set subimage [$imageLib slice $im $x $y $spriteWidth $spriteHeight]
Wish $p displays image $subimage with {*}$options
}
}} with environment {{this builtin-programs/sprites.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when the image loader is /loadImage/ {When /someone/ wishes /p/ displays image /impath/ with /...opti (
[ m909:0 () ]
[ m949:0 () ]
[ m970:0 () ]
[ m1004:0 (s1775:0) ]
)when the image loader is /loadImage/ {When /someone/ wishes /p/ displays image /impath/ with /...options/ & /p/ has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n} with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when the image loader is /loadImage/ \n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ (
[ m1455:0 (s2338:0 s2339:0 s2342:0 s2343:0 s2349:0 s2350:0 s2353:0 s2354:0) ]
)when the image loader is /loadImage/ \n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>}}
when the program save directory is /saveDir/ \n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ (
[ m830:0 (s1281:0) ]
[ m831:0 (s1273:0) ]
)when the program save directory is /saveDir/ \n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {}
when the program save directory is /saveDir/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ e (
[ m938:0 (s1273:0) ]
[ m939:0 (s1820:0 s1822:0 s1825:0 s1826:0 s1827:0 s1829:0) ]
)when the program save directory is /saveDir/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {}}
when the program save directory is /saveDir/ {
fn printProgram {printer id code} {
if {[ (
[ m1043:0 (s1273:0) ]
[ m1044:0 (s1828:0) ]
)when the program save directory is /saveDir/ {
fn printProgram {printer id code} {
if {[file exists "$saveDir/$id.folk"]} {
error "Program $id already exists on disk. Aborting print."
}
writeFolkFile $id $code
writeMetaFile $printer $id
Expect! $printer is at /address/
set printerSocket [socket stream ${address}:9100]
fconfigure $printerSocket -translation binary -buffering none
set template {
[init]
[tag $id]
[feed 1]
$id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])
[feed 2]
$code
[feed 3]
[cut]
}
puts -nonewline $printerSocket [render $template]
close $printerSocket
}
fn render {template} {
set trimmed [lmap line [split $template "\n"] { string trim $line }]
set singleLine [join $trimmed ""]
return [uplevel [list subst $singleLine]]
}
fn writeFolkFile {id code} {
set folkFile [open "$saveDir/$id.folk" w]
puts $folkFile $code
close $folkFile
}
fn writeMetaFile {printer id} {
Expect! $printer has tag geometry /geometry/
set metaFile [open "$saveDir/$id.meta.folk" w]
puts $metaFile [subst {Claim tag \$this has geometry {$geometry}}]
close $metaFile
}
fn cut {} {
return "\x1dV\x0"
}
fn feed n {
return [format "\x1b\x64%c" $n]
}
fn init {} {
return "\x1b\x40"
}
fn raw number {
return [format "%c" $number]
}
fn scaledAprilTag {id scale} {
set tagImage [$printLib tagImageForId $id]
set tagBits [list]
for {set y 0} {$y < 10} {incr y} {
for {set i 0 } {$i < $scale} {incr i} {
for {set x 0} {$x < 10} {incr x} {
set j [expr {$y * [$imageLib Image_bytesPerRow $tagImage] + $x}]
set bit [expr {[$imageLib Image_data $tagImage $j] != 255}]
lappend tagBits {*}[lrepeat $scale $bit]
}
}
}
return $tagBits
}
# scale must be divisible by 4 so width will be divisible by 8
fn tag {id {scale 12}} {
set tagBits [scaledAprilTag $id $scale]
set width [expr {10 * $scale}]
set xL [expr {$width / 8}] ;# width in bytes (low byte)
set yL [expr {$width % 256}] ;# height in lines (low byte)
set yH [expr {$width / 256}] ;# height in lines (high byte)
return "\x1dv0\x03[raw $xL]\x00[raw $yL][raw $yH][binary format B* [join $tagBits ""]]"
}
Subscribe: print program /id/ on receipt printer /printer/ with code /code/ {
printProgram $printer $id $code
}
} with environment {{this builtin-programs/esc-pos.folk} {} {} {printLib <C:cfileDzXJHE>} {} {imageLib <C:cfileV8MUaU>} {}}
when the program save directory is /programDir/ {When the editor utils library is /utils/ \n\n#\ TODO (
[ m827:0 (s1273:0) ]
[ m828:0 (s1274:0) ]
)when the program save directory is /programDir/ {When the editor utils library is /utils/ \n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n} with environment {{this builtin-programs/editor/editor.folk} {} {}}
when the program save directory is /programDirectory/ {When saving is ready \n\n\ \ \ \ #\ HACK:\ A\ (
[ m840:0 (s1273:0) ]
[ m841:0 (s1295:0) ]
)when the program save directory is /programDirectory/ {When saving is ready \n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n} with environment {{this builtin-programs/saving/migrate.folk} {} {} {holdDirectory /home/folk/folk-data/hold} {}}
when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/errors.folk {builtin-p (
[ m21549:1066 () ]
[ m21682:1067 () ]
[ m21911:1067 () ]
[ m22035:1066 () ]
[ m22131:1067 () ]
[ m22327:1021 () ]
[ m22397:1021 () ]
[ m22488:1066 () ]
[ m22623:1046 () ]
[ m22740:1064 () ]
[ m22830:1065 () ]
[ m22974:1067 () ]
[ m23043:1067 () ]
[ m23282:1054 () ]
[ m23307:1044 () ]
[ m23497:1066 () ]
[ m23717:1067 () ]
[ m23917:1066 () ]
[ m24001:1064 () ]
[ m24149:1067 () ]
[ m24264:1056 () ]
[ m24401:675 () ]
[ m24566:703 () ]
[ m24653:1064 () ]
[ m24772:1066 () ]
[ m24938:1067 () ]
[ m25044:1062 () ]
[ m25193:1067 () ]
[ m25322:1064 () ]
[ m25494:1067 () ]
[ m25594:1067 () ]
[ m25807:1067 (s7232:1265) ]
)when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/errors.folk {builtin-programs/errors.folk 2} {the clock time is /t/}};
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
} with environment {{this builtin-programs/errors.folk} {} {} {p builtin-programs/terminal.folk err {FIXME: terminal.folk not currently working.} info {-code 1 -level 0 -errorinfo {evaluateBlock builtin-programs/terminal.folk 26 {error {FIXME: terminal.folk not currently working.}} evaluateBlock prelude.tcl 185:8 {apply {{this __envStack __env} #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n} builtin-programs/terminal.folk {{this builtin-programs/terminal.folk} {}} {this builtin-programs/terminal.folk __envStack {{this builtin-programs/terminal.folk} {}}}} {} {} 1 {evaluateBlock #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n {{this builtin-programs/terminal.folk} {}}}} -errorcode NONE}} {}}
when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/errors.folk {builtin-p (
[ m25810:1062 (s7236:1261) ]
)when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/errors.folk {builtin-programs/errors.folk 2} {the clock time is /t/}};
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
} with environment {{this builtin-programs/errors.folk} {} {} {p builtin-programs/terminal-ui.folk err {can't read "::env(TERM)": no such element in array} info {-code 1 -level 0 -errorinfo {evaluateBlock builtin-programs/terminal-ui.folk 11 {if {$::env(TERM) eq "dumb"} {
return
}} evaluateBlock prelude.tcl 185:8 {apply {{this __envStack __env} {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}} builtin-programs/terminal-ui.folk {{this builtin-programs/terminal-ui.folk} {}} {this builtin-programs/terminal-ui.folk __envStack {{this builtin-programs/terminal-ui.folk} {}}}} {} {} 1 {evaluateBlock {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
} {{this builtin-programs/terminal-ui.folk} {}}}} -errorcode NONE}} {}}
when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/draw/gif.folk {builtin (
[ m21377:1067 () ]
[ m21554:1067 () ]
[ m21687:1064 () ]
[ m21914:1036 () ]
[ m22050:992 () ]
[ m22133:1066 () ]
[ m22331:1020 () ]
[ m22404:1067 () ]
[ m22492:1057 () ]
[ m22626:1050 () ]
[ m22742:1065 () ]
[ m22833:1067 () ]
[ m22976:1065 () ]
[ m23048:1067 () ]
[ m23290:1067 () ]
[ m23314:1064 () ]
[ m23502:1066 () ]
[ m23722:1067 () ]
[ m23921:1067 () ]
[ m24008:1067 () ]
[ m24151:1067 () ]
[ m24268:1040 () ]
[ m24405:677 (s5622:1264) ]
[ m24568:706 (s5622:1264) ]
[ m24660:1067 (s5622:1264) ]
[ m24774:1059 (s5622:1264) ]
[ m24948:1067 (s5622:1264) ]
[ m25047:1066 (s5622:1264) ]
[ m25196:1058 (s5622:1264) ]
[ m25327:1065 (s5622:1264) ]
[ m25502:1067 (s5622:1264) ]
[ m25607:1067 (s5622:1264) ]
[ m25812:1060 (s5622:1264) ]
)when the clock time is /t/ {__setFreshAtomicallyVersionOnKey {builtin-programs/draw/gif.folk {builtin-programs/draw/gif.folk 23} {the clock time is /t/}};
set ms [expr {int($t * 1000) % $totalDuration}]
set frameIdx 0
foreach cd $cumulativeDelays {
if {$ms < $cd} { break }
incr frameIdx
}
if {$frameIdx >= [llength $frames]} { set frameIdx 0 }
set im [lindex $frames $frameIdx]
Wish $p displays image $im with {*}$options
} with environment {{this builtin-programs/draw/gif.folk} {} {} {gifLib <C:cfiled3kiwc>} {} {p 11 gif {frames {{width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0346e20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03558a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b035cde0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0364320}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b036b860}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0372da0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b037a2e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0381820}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0388d60}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03902a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03977e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b039ed20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03a6260}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03ad7a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03b4ce0}}} delays {250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250} width 100 height 100} options {scale 1.0}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {cumulativeDelays {250 500 750 1000 1250 1500 1750 2000 2250 2500 2750 3000 3250 3500 3750 4000} totalDuration 4000 d 250 delays {250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250} frames {{width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0346e20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03558a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b035cde0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0364320}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b036b860}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0372da0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b037a2e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0381820}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0388d60}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03902a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03977e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b039ed20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03a6260}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03ad7a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03b4ce0}}}}}
when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ ()when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 1 i 2 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0743329102974 -0.247183628223 0.681487571986} {-0.0682122450524 -0.304199509606 0.65468054442} {-0.0315547948064 -0.309297558752 0.673893332774} {-0.0376754600574 -0.25228167737 0.70070036035}}}} {slice {width {107} height {70} components {3} bytesPerRow {321} uniq {-781439560} data {(uint8_t*) 0x79cd13e88af0}}} {}}
when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ ()when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 2 i 3 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0682122450493 -0.304199509606 0.654680544415} {-0.0620915798043 -0.361215390989 0.627873516849} {-0.0254341295583 -0.366313440135 0.647086305203} {-0.0315547948093 -0.309297558753 0.673893332779}}}} {slice {width {117} height {77} components {3} bytesPerRow {351} uniq {-781439560} data {(uint8_t*) 0x79cd13fe61c0}}} {}}
when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ ()when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 1 col 0 i 4 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0437961253023 -0.195265795986 0.727507387917} {-0.0376754600573 -0.252281677369 0.700700360351} {-0.00101800981133 -0.257379726515 0.719913148705} {-0.00713867506233 -0.200363845133 0.746720176281}}}} {slice {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}}} {}}
when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ ()when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 0 i 1 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0804535755455 -0.190167746839 0.708294599558} {-0.0743329103005 -0.247183628222 0.681487571992} {-0.0376754600545 -0.252281677368 0.700700360346} {-0.0437961253055 -0.195265795986 0.727507387922}}}} {slice {width {97} height {64} components {3} bytesPerRow {291} uniq {-781439560} data {(uint8_t*) 0x79cd13f19940}}} {}}
when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ ()when the clock time is /t/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 1 col 1 i 5 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0376754600542 -0.25228167737 0.700700360345} {-0.0315547948092 -0.309297558753 0.673893332779} {0.00510265543677 -0.314395607899 0.693106121133} {-0.00101800981423 -0.257379726517 0.719913148709}}}} {slice {width {104} height {68} components {3} bytesPerRow {312} uniq {-781439560} data {(uint8_t*) 0x79cd13f263f0}}} {}}
when the print library is /printLib/ {When the image library is /imageLib/ & the program save directo (
[ m1041:0 (s1821:0) ]
)when the print library is /printLib/ {When the image library is /imageLib/ & the program save directory is /saveDir/ {
fn printProgram {printer id code} {
if {[file exists "$saveDir/$id.folk"]} {
error "Program $id already exists on disk. Aborting print."
}
writeFolkFile $id $code
writeMetaFile $printer $id
Expect! $printer is at /address/
set printerSocket [socket stream ${address}:9100]
fconfigure $printerSocket -translation binary -buffering none
set template {
[init]
[tag $id]
[feed 1]
$id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])
[feed 2]
$code
[feed 3]
[cut]
}
puts -nonewline $printerSocket [render $template]
close $printerSocket
}
fn render {template} {
set trimmed [lmap line [split $template "\n"] { string trim $line }]
set singleLine [join $trimmed ""]
return [uplevel [list subst $singleLine]]
}
fn writeFolkFile {id code} {
set folkFile [open "$saveDir/$id.folk" w]
puts $folkFile $code
close $folkFile
}
fn writeMetaFile {printer id} {
Expect! $printer has tag geometry /geometry/
set metaFile [open "$saveDir/$id.meta.folk" w]
puts $metaFile [subst {Claim tag \$this has geometry {$geometry}}]
close $metaFile
}
fn cut {} {
return "\x1dV\x0"
}
fn feed n {
return [format "\x1b\x64%c" $n]
}
fn init {} {
return "\x1b\x40"
}
fn raw number {
return [format "%c" $number]
}
fn scaledAprilTag {id scale} {
set tagImage [$printLib tagImageForId $id]
set tagBits [list]
for {set y 0} {$y < 10} {incr y} {
for {set i 0 } {$i < $scale} {incr i} {
for {set x 0} {$x < 10} {incr x} {
set j [expr {$y * [$imageLib Image_bytesPerRow $tagImage] + $x}]
set bit [expr {[$imageLib Image_data $tagImage $j] != 255}]
lappend tagBits {*}[lrepeat $scale $bit]
}
}
}
return $tagBits
}
# scale must be divisible by 4 so width will be divisible by 8
fn tag {id {scale 12}} {
set tagBits [scaledAprilTag $id $scale]
set width [expr {10 * $scale}]
set xL [expr {$width / 8}] ;# width in bytes (low byte)
set yL [expr {$width % 256}] ;# height in lines (low byte)
set yH [expr {$width / 256}] ;# height in lines (high byte)
return "\x1dv0\x03[raw $xL]\x00[raw $yL][raw $yH][binary format B* [join $tagBits ""]]"
}
Subscribe: print program /id/ on receipt printer /printer/ with code /code/ {
printProgram $printer $id $code
}
}} with environment {{this builtin-programs/esc-pos.folk} {} {}}
when the print library is /printLib/ {When the calibration model library is /modelLib/ & the calibrat (
[ m1045:0 (s1830:0) ]
)when the print library is /printLib/ {When the calibration model library is /modelLib/ & the calibration matrix library is /matLib/ \n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n} with environment {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70}}
when the print library is /printLib/ {When /p/ has canvas /writableTexture/ with /...wiOptions/ & /p/ (
[ m1049:0 (s1833:0) ]
)when the print library is /printLib/ {When /p/ has canvas /writableTexture/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ & /someone/ wishes to draw an AprilTag onto /p/ with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when the default program geometry is /defaultGeom/ {When program /program/ is scaled by x /xScale/ y (
[ m673:0 () ]
[ m677:0 () ]
[ m926:0 (s1607:0) ]
)when the default program geometry is /defaultGeom/ {When program /program/ is scaled by x /xScale/ y /yScale/ {
proc extractMm {mm} {
regexp {([0-9.]+)mm} $mm -> extracted
return $extracted
}
set tagSize [extractMm [dict get $defaultGeom tagSize]]
set left [extractMm [dict get $defaultGeom left]]
set right [extractMm [dict get $defaultGeom right]]
set top [extractMm [dict get $defaultGeom top]]
set bottom [extractMm [dict get $defaultGeom bottom]]
set width [expr {$left + $tagSize + $right}]
set height [expr {$top + $tagSize + $bottom}]
set right $($right + ($width * $xScale - $width))mm
set bottom $($bottom + ($height * $yScale - $height))mm
set newGeom [list tagSize ${tagSize}mm left ${left}mm right ${right}mm top ${top}mm bottom ${bottom}mm]
Claim tag $program has geometry $newGeom
}} with environment {{this builtin-programs/tags-geometry.folk} {} {}}
when the default program geometry is /defaultGeom/ {When /someone/ wishes /tag/ has resolved geometry (
[ m672:0 () ]
[ m676:0 () ]
[ m925:0 (s1606:0) ]
)when the default program geometry is /defaultGeom/ {When /someone/ wishes /tag/ has resolved geometry \n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/tags-geometry.folk} {} {}}
when the jpeg library is /jpegLib/ {
fn jpegLoader {im} {
if {[string match "*jpg" $im] | (
[ m1000:0 (s1772:0) ]
)when the jpeg library is /jpegLib/ {
fn jpegLoader {im} {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
}
Claim [fn jpegLoader] is an image loader
} with environment {{this builtin-programs/draw/image.folk} {} {}}
when the jpeg library is /jpegLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\ (
[ m1008:0 (s1779:0) ]
)when the jpeg library is /jpegLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n with environment {{this builtin-programs/web/camera-frame.folk} {} {}}
when the jpeg library is /jpegLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-fram (
[ m1006:0 (s1777:0) ]
)when the jpeg library is /jpegLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n with environment {{this builtin-programs/web/apriltag-frame.folk} {} {}}
when the jpeg library is /jpegLib/ \n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ (
[ m1002:0 (s2398:0 s2399:0) ]
)when the jpeg library is /jpegLib/ \n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when the jpeg library is /jpegLib/ {When the calibration model library is /modelLib/ & the calibratio (
[ m23569:0 (s31213:0) ]
)when the jpeg library is /jpegLib/ {When the calibration model library is /modelLib/ & the calibration matrix library is /matLib/ & /someone/ wishes to calibrate camera {$camera} to display {$display} using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {display monitor displayWidth 4096 displayHeight 2160} {} {makeAprilTagDetector {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}}}}}} {}}
when the png library is /pngLib/ {
fn pngLoader {im} {
if {[string match "*png" $im]} {
(
[ m966:0 (s1733:0) ]
)when the png library is /pngLib/ {
fn pngLoader {im} {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
}
Claim [fn pngLoader] is an image loader
} with environment {{this builtin-programs/draw/image.folk} {} {}}
when the gif library is /gifLib/ {
fn gifLoader {im} {
upvar coerceToImage coerceToImage
(
[ m946:0 (s1658:0) ]
)when the gif library is /gifLib/ {
fn gifLoader {im} {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
}
Claim [fn gifLoader] is an image loader
} with environment {{this builtin-programs/draw/image.folk} {} {}}
when the gif library is /gifLib/ \n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /... (
[ m945:0 (s1657:0) ]
)when the gif library is /gifLib/ \n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n with environment {{this builtin-programs/draw/gif.folk} {} {}}
when the color map is /colorMap/ \n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...option (
[ m492:0 (s783:0 s792:0 s796:0) ]
)when the color map is /colorMap/ \n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/draw/fill.folk} {} {}}
when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas proje (
[ m496:0 (s795:0) ]
)when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ & /someone/ wishes to draw a dashed line onto /p/ with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {}}
when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas proje (
[ m493:0 (s786:0) ]
)when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ & /someone/ wishes to draw a line onto /p/ with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {}}
when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas proje (
[ m488:0 (s779:0) ]
)when the color map is /colorMap/ {When /p/ has canvas /id/ with /...wiOptions/ & /p/ has canvas projection /surfaceToClip/ & /someone/ wishes to draw a circle onto /p/ with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {}}
when the color map is /colorMap/ {When /someone/ wishes to draw text onto /p/ with /...options/ \n\ \ (
[ m1456:0 (s2331:0) ]
)when the color map is /colorMap/ {When /someone/ wishes to draw text onto /p/ with /...options/ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>}}
when the db library is /dbLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\} (
[ m47716:0 (s60092:0) ]
)when the db library is /dbLib/ \n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n with environment {{this builtin-programs/web/dep-graph.folk} {} {getDotAsPdf {{dot} {
set fd [open |[list dot -Tpdf <<$dot] r]
fconfigure $fd -translation binary
set response [read $fd]
try {
close $fd
return $response
} on error e {
if {[catch {exec which dot}]} {
error "graphviz not installed!"
}
}
}} dbDotify {{dbLib db} {
set dot [list]
set matchRefs [dict create]
foreach stmt [Query! /...anything/] {
set stmtRef [dict get $stmt __ref]
set label [$dbLib clause $db $stmtRef]
set label [join [lmap line [split $label "\n"] {
expr { [string length $line] > 80 ? "[string range $line 0 80]..." : $line }
}] "\n"]
set label [string map {"\"" "\\\""} [string map {"\\" "\\\\"} $label]]
set stmtParentCount [$dbLib statementParentCount $db $stmtRef]
set stmtPtrCount [$dbLib statementPtrCount $db $stmtRef]
lappend dot "<$stmtRef> \[label=\"$stmtRef ($stmtParentCount parents) ($stmtPtrCount ptrs): $label\"\];"
foreach childMatchRef [$dbLib childMatches $db $stmtRef] {
lappend dot "<$stmtRef> -> <$childMatchRef>;"
dict set matchRefs $childMatchRef true
}
}
foreach {matchRef _} $matchRefs {
set match [$dbLib matchAcq $db $matchRef]
if {$match eq "(Match*) 0x0"} { continue }
set matchPtrCount [$dbLib matchPtrCount $db $matchRef]
set matchIsAlive [$dbLib matchIsAlive $db $matchRef]
lappend dot "<$matchRef> \[label=\"$matchRef (alive? $matchIsAlive) ($matchPtrCount)\"\];"
foreach childStatementRef [$dbLib childStatements $db $matchRef] {
lappend dot "<$matchRef> -> <$childStatementRef>;"
}
$dbLib matchRel $db $match
}
return "digraph { rankdir=LR; [join $dot "\n"] }"
}}}}
when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with ha (
[ m47710:0 (s60086:0) ]
)when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
} with environment {{this builtin-programs/web/holds.folk} {} {}}
when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" wi (
[ m47698:0 (s60072:0) ]
)when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
} with environment {{this builtin-programs/web/statements.folk} {} {}}
when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" w (
[ m47692:0 (s60067:0) ]
)when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
} with environment {{this builtin-programs/web/atomicallys.folk} {} {}}
when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with h (
[ m47677:0 (s60051:0) ]
)when the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
} with environment {{this builtin-programs/web/report.folk} {} {}}
when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU draw library is /dra (
[ m2250:0 (s3344:0) ]
)when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU draw library is /drawLib/ & the GPU VMA DLL is /vmaDll/ & the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cflags -I./vendor
$cc endcflags $vmaDll
$cc include <png.h>
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
#include "vk_mem_alloc.h"
VmaAllocator vmaGetAllocator();
VkDevice device;
}
# HACK: to make gpuLib extend properly
$cc typedef {struct PushConstantsEncoder} PushConstantsEncoder
$cc typedef {struct Pipeline} Pipeline
$cc typedef {struct VmaAllocation_T*} VmaAllocation
$cc argtype VmaAllocation {
VmaAllocation $argname;
sscanf(Jim_String($obj), "(VmaAllocation) %p", &$argname);
}
$cc rtype VmaAllocation {
char buf[100];
snprintf(buf, 100, "(VmaAllocation) %p", $rvalue);
$robj = Jim_NewStringObj(interp, buf, -1);
}
$cc extend $gpuLib
$cc extend $imageLib
$cc extend $gpuTextureLib
$cc proc texturesLibInit {} void {
volkInitialize();
volkLoadInstanceOnly(*instance_ptr());
device = *device_ptr();
volkLoadDevice(device);
}
$cc proc copyTextureFromGpu {GpuTextureHandle han} Image {
GpuTextureBlock* block = getGpuTexture(han);
if (!block->alive) {
return (Image){0};
}
Image im = {
.width = block->width,
.height = block->height,
.components = 4, // HACK: hard-coded for now
.bytesPerRow = block->width * 4,
.data = malloc(block->width * block->height * 4)
};
VkBuffer stagingBuffer;
VmaAllocation stagingBufferAllocation;
size_t stagingBufferSize = block->width * block->height * 4;
createBuffer(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&stagingBuffer, &stagingBufferAllocation);
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = block->textureImage,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT
};
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
// Copy image to buffer
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {block->width, block->height, 1}
};
vkCmdCopyImageToBuffer(
commandBuffer,
block->textureImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
stagingBuffer,
1,
®ion
);
// Transition image layout back
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkFence fence = getFence();
endSingleTimeCommands(commandBuffer, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Copy staging buffer back to CPU
void* data;
vmaMapMemory(vmaGetAllocator(), stagingBufferAllocation, &data);
memcpy(im.data, data, stagingBufferSize);
vmaUnmapMemory(vmaGetAllocator(), stagingBufferAllocation);
// Cleanup staging buffer
vmaDestroyBuffer(vmaGetAllocator(), stagingBuffer, stagingBufferAllocation);
return im;
}
$cc code {
struct WriteState {
uint8_t* buffer;
size_t* size;
};
void pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
struct WriteState* state = (struct WriteState*)png_get_io_ptr(png_ptr);
memcpy(state->buffer + *state->size, data, length);
*state->size += length;
}
}
$cc proc imageToPngBuffer {Image im size_t* outSize} uint8_t* {
size_t bufferSize = im.width * im.height * im.components * 2; // max size estimate
uint8_t* buffer = malloc(bufferSize);
*outSize = 0;
png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_w) {
free(buffer);
return NULL;
}
png_infop info_w = png_create_info_struct(png_w);
if (!info_w) {
png_destroy_write_struct(&png_w, NULL);
free(buffer);
return NULL;
}
struct WriteState state = {
.buffer = buffer,
.size = outSize
};
png_set_write_fn(png_w, &state, pngWriteCallback, NULL);
if (im.components == 4) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else if (im.components == 3) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_destroy_write_struct(&png_w, &info_w);
free(buffer);
return NULL;
}
png_bytep* row_pointers = malloc(sizeof(png_bytep) * im.height);
for (int y = 0; y < im.height; y++) {
row_pointers[y] = im.data + y * im.bytesPerRow;
}
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
png_destroy_write_struct(&png_w, &info_w);
*outSize = bufferSize;
return buffer;
}
$cc proc copyAllTexturesFromGpu {} Jim_Obj* {
Jim_Obj* ret = Jim_NewListObj(interp, NULL, 0);
for (int i = 0; i < getMaxTextures(); i++) {
if (getGpuTexture(i)->alive) {
Image im = copyTextureFromGpu(i);
size_t pngSize;
uint8_t* pngData = imageToPngBuffer(im, &pngSize);
Jim_ListAppendElement(interp, ret, Jim_ObjPrintf("Image %d (%d x %d)", i, im.width, im.height));
Jim_ListAppendElement(interp, ret, Jim_NewStringObj(interp, (char*)pngData, pngSize));
free(pngData);
free(im.data);
}
}
return ret;
}
set texturesLib [$cc compile]
$texturesLib texturesLibInit
Wish the web server handles route {/textures} with handler {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
}
}} with environment {{this builtin-programs/web/textures.folk} {} {}}
when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU texture library is / (
[ m2249:0 (s3346:0) ]
)when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU texture library is /gpuTextureLib/ \n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n} with environment {{this builtin-programs/gpu/pipelines.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {}}
when the GPU library is /gpuLib/ {When the GPU VMA DLL is /vmaDll/ & the image library is /imageLib/ (
[ m2251:0 (s3349:0) ]
)when the GPU library is /gpuLib/ {When the GPU VMA DLL is /vmaDll/ & the image library is /imageLib/ \n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n} with environment {{this builtin-programs/gpu/textures.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {}}
when the GPU library is /gpuLib/ {When the GPU Vulkan handle type definer is /defineVulkanHandleType/ (
[ m2252:0 (s3348:0) ]
)when the GPU library is /gpuLib/ {When the GPU Vulkan handle type definer is /defineVulkanHandleType/ & the GPU texture library is /gpuTextureLib/ & the GPU pipeline library is /pipelineLib/ & the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n} with environment {{this builtin-programs/gpu/draw.folk} {} {}}
when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU pipeline library is (
[ m2253:0 (s3347:0) ]
)when the GPU library is /gpuLib/ {When the image library is /imageLib/ & the GPU pipeline library is /pipelineLib/ & the GPU texture library is /gpuTextureLib/ \n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/gpu/canvases.folk} {} {}}
when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU library is /gpuLib/ (
[ m737:0 (s1136:0) ]
)when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU library is /gpuLib/ & the image library is /imageLib/ & the GPU texture library is /gpuTextureLib/ \n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n} with environment {{this builtin-programs/gpu/pipelines.folk} {} {}}
when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU library is /gpuLib/ (
[ m744:0 (s1146:0) ]
)when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU library is /gpuLib/ & the GPU VMA DLL is /vmaDll/ & the image library is /imageLib/ \n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n} with environment {{this builtin-programs/gpu/textures.folk} {} {}}
when the GPU Vulkan handle type definer is /defineVulkanHandleType/ \n\nfn\ defineVulkanHandleType\n\ (
[ m771:0 (s18539:0) ]
)when the GPU Vulkan handle type definer is /defineVulkanHandleType/ \n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n with environment {{this builtin-programs/gpu/vma.folk} {} {}}
when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU pipeline library is (
[ m898:0 (s1394:0) ]
)when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU pipeline library is /pipelineLib/ \n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n} with environment {{this builtin-programs/gpu/toy-shader.folk} {} {sha1Lib <C:cfileq8Ho0l> cc ::<reference.<C______>.00000000000000000004>}}
when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU texture library is (
[ m2257:0 (s3352:0) ]
)when the GPU Vulkan handle type definer is /defineVulkanHandleType/ {When the GPU texture library is /gpuTextureLib/ & the GPU pipeline library is /pipelineLib/ & the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n} with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {}}
when the GPU pipeline library is /pipelineLib/ \n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy (
[ m20733:0 (s27906:0) ]
)when the GPU pipeline library is /pipelineLib/ \n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/gpu/toy-shader.folk} {} {sha1Lib <C:cfileq8Ho0l> cc ::<reference.<C______>.00000000000000000004>} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {}}
when the GPU pipeline library is /pipelineLib/ {When the GPU texture library is /gpuTextureLib/ \n\ \ (
[ m20732:0 (s27449:0) ]
)when the GPU pipeline library is /pipelineLib/ {When the GPU texture library is /gpuTextureLib/ \n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {}}
when the GPU pipeline library is /pipelineLib/ {When the GPU pipeline compiler library is /pipelineCo (
[ m20731:0 (s27450:0) ]
)when the GPU pipeline library is /pipelineLib/ {When the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n} with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuTextureLib <C:cfileHQKyt3>} {}}
when the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ (
[ m20735:0 (s30971:0 s30974:0 s30975:0) ]
)when the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuTextureLib <C:cfileHQKyt3>} {} {pipelineLib <C:cfilekUErd7>} {}}
when the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} dat (
[ m18012:0 (s23880:0) ]
)when the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c298ac0}} as texture /gim/ \n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {^loadImage {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} ^loadFont {name \n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ {builtin-programs/draw/text.folk 174}} glyphIdx {} glyphInfos {{advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {0 0 0 0} atlasBounds {0 0 0 0}} {advance 0.54545454545454541 planeBounds {0.16367177126670798 -0.047790563866513223 0.38178277418783751 0.76233601841196774} atlasBounds {0.5 117.5 7.5 143.5}} {advance 0.54545454545454541 planeBounds {0.070195627157652457 0.38622952996370719 0.47525891829689293 0.76013410639992918} atlasBounds {20.5 1.5 33.5 13.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403044 -0.041426927502876881 0.5687350624059484 0.76869965477560409} atlasBounds {25.5 117.5 44.5 143.5}} {advance 0.54545454545454541 planeBounds {0.0042418341152518444 -0.11705098698769585 0.5339399840665664 0.84886916880587771} atlasBounds {137.5 176.5 154.5 207.5}} {advance 0.54545454545454541 planeBounds {-0.038859874302912295 -0.04142692750287686 0.58431441975745768 0.76869965477560409} atlasBounds {80.5 117.5 100.5 143.5}} {advance 0.54545454545454541 planeBounds {-0.02646233513322124 -0.057006284854386136 0.56555324422413022 0.78427901212711337} atlasBounds {0.5 144.5 19.5 171.5}} {advance 0.54545454545454541 planeBounds {0.17925112861821724 0.38622952996370719 0.36620341683632823 0.76013410639992918} atlasBounds {43.5 1.5 49.5 13.5}} {advance 0.54545454545454541 planeBounds {0.10453616004248915 -0.16606178631495083 0.44728202177569265 0.89333451358767813} atlasBounds {42.5 173.5 53.5 207.5}} {advance 0.54545454545454541 planeBounds {0.098172523678852791 -0.16606178631495083 0.4409183854120563 0.89333451358767813} atlasBounds {69.5 173.5 80.5 207.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998937787 0.068083119412233314 0.55315570505443923 0.66009869876958482} atlasBounds {174.5 16.5 192.5 35.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403006 0.067628573957687899 0.56873506240594851 0.65964415331503945} atlasBounds {188.5 64.5 207.5 83.5}} {advance 0.54545454545454541 planeBounds {0.13400150482428963 -0.21740683367265645 0.38327122244843759 0.15649774276356557} atlasBounds {34.5 1.5 42.5 13.5}} {advance 0.54545454545454541 planeBounds {0.054616269806143224 0.28573957687881735 0.49083827564840227 0.44153315039390983} atlasBounds {193.5 30.5 207.5 35.5}} {advance 0.54545454545454541 planeBounds {0.16367177126670798 -0.056782774187837462 0.38178277418783751 0.16132822873329206} atlasBounds {99.5 6.5 106.5 13.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154556 -0.19709568912100559 0.53757634770292995 0.89345932548464191} atlasBounds {0.5 172.5 17.5 207.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154417 -0.057006284854386136 0.53757634770292995 0.78427901212711337} atlasBounds {20.5 144.5 37.5 171.5}} {advance 0.54545454545454541 planeBounds {0.045525360715234137 -0.041426927502876881 0.48174736655749317 0.76869965477560409} atlasBounds {138.5 117.5 152.5 143.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.035063291139240498 0.53750059012717244 0.77506329113924044} atlasBounds {153.5 117.5 170.5 143.5}} {advance 0.54545454545454541 planeBounds {0.023457555103124729 -0.057006284854386136 0.52199699035142078 0.78427901212711337} atlasBounds {191.5 180.5 207.5 207.5}} {advance 0.54545454545454541 planeBounds {0.006514561387979111 -0.041426927502876881 0.53621271133929371 0.76869965477560409} atlasBounds {114.5 90.5 131.5 116.5}} {advance 0.54545454545454541 planeBounds {0.013332743206160949 -0.047790563866513223 0.54303089315747555 0.76233601841196774} atlasBounds {150.5 90.5 167.5 116.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154712 -0.057006284854386136 0.53757634770292995 0.78427901212711337} atlasBounds {38.5 144.5 55.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0056054704788881726 -0.041426927502876881 0.53530362043020263 0.76869965477560409} atlasBounds {57.5 36.5 74.5 62.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154452 -0.057006284854386136 0.53757634770292995 0.78427901212711337} atlasBounds {56.5 144.5 73.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154712 -0.057006284854386136 0.53757634770292995 0.78427901212711337} atlasBounds {74.5 144.5 91.5 171.5}} {advance 0.54545454545454541 planeBounds {0.16367177126670798 -0.046711958927148821 0.38178277418783751 0.60762104983623966} atlasBounds {199.5 41.5 206.5 62.5}} {advance 0.54545454545454541 planeBounds {0.13400150482428963 -0.22291537576347703 0.38327122244843759 0.61836992121802248} atlasBounds {92.5 144.5 100.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0069691068425245528 -0.010268212799858369 0.53666725679383898 0.73754094007258564} atlasBounds {126.5 38.5 143.5 62.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403006 0.17668407541825262 0.56873506240594851 0.55058865185447459} atlasBounds {0.5 1.5 19.5 13.5}} {advance 0.54545454545454541 planeBounds {0.0087872886607063706 -0.010268212799858369 0.53848543861202081 0.73754094007258564} atlasBounds {108.5 38.5 125.5 62.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} {advance 0.54545454545454541 planeBounds {-0.038859874302912309 -0.041426927502876895 0.58431441975745768 0.76869965477560409} atlasBounds {17.5 36.5 37.5 62.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998938021 -0.041426927502876881 0.55315570505443923 0.76869965477560409} atlasBounds {38.5 36.5 56.5 62.5}} {advance 0.54545454545454541 planeBounds {0.031639373284942894 -0.041426927502876881 0.53017880853323884 0.76869965477560409} atlasBounds {0.5 36.5 16.5 62.5}} {advance 0.54545454545454541 planeBounds {0.0087872886607063862 -0.057006284854386136 0.53848543861202092 0.78427901212711337} atlasBounds {119.5 144.5 136.5 171.5}} {advance 0.54545454545454541 planeBounds {0.0196963795697973 -0.041426927502876881 0.5493945295211119 0.76869965477560409} atlasBounds {170.5 63.5 187.5 89.5}} {advance 0.54545454545454541 planeBounds {0.036184827830397462 -0.041426927502876881 0.53472426307869347 0.76869965477560409} atlasBounds {153.5 63.5 169.5 89.5}} {advance 0.54545454545454541 planeBounds {0.03709391873948837 -0.041426927502876881 0.53563335398778444 0.76869965477560409} atlasBounds {136.5 63.5 152.5 89.5}} {advance 0.54545454545454541 planeBounds {0.013332743206160911 -0.057006284854386136 0.54303089315747544 0.78427901212711337} atlasBounds {137.5 144.5 154.5 171.5}} {advance 0.54545454545454541 planeBounds {0.023457555103124715 -0.041426927502876881 0.52199699035142066 0.76869965477560409} atlasBounds {102.5 63.5 118.5 89.5}} {advance 0.54545454545454541 planeBounds {0.054616269806143224 -0.041426927502876881 0.49083827564840227 0.76869965477560409} atlasBounds {87.5 63.5 101.5 89.5}} {advance 0.54545454545454541 planeBounds {-0.012121802248384529 -0.047790563866513223 0.51757634770292993 0.76233601841196774} atlasBounds {69.5 63.5 86.5 89.5}} {advance 0.54545454545454541 planeBounds {0.034241834115251828 -0.041426927502876881 0.56393998406656631 0.76869965477560409} atlasBounds {51.5 63.5 68.5 89.5}} {advance 0.54545454545454541 planeBounds {0.051309639727361231 -0.041426927502876881 0.51869036027263871 0.76869965477560409} atlasBounds {35.5 63.5 50.5 89.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154643 -0.041426927502876881 0.53757634770292995 0.76869965477560409} atlasBounds {17.5 63.5 34.5 89.5}} {advance 0.54545454545454541 planeBounds {0.023457555103124708 -0.041426927502876881 0.52199699035142066 0.76869965477560409} atlasBounds {0.5 63.5 16.5 89.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154417 -0.057006284854386136 0.53757634770292995 0.78427901212711337} atlasBounds {155.5 144.5 172.5 171.5}} {advance 0.54545454545454541 planeBounds {0.042093918739488347 -0.041426927502876881 0.54063335398778434 0.76869965477560409} atlasBounds {168.5 90.5 184.5 116.5}} {advance 0.54545454545454541 planeBounds {0.0049013012304151751 -0.18932371426042316 0.59691688058776671 0.77659644153315044} atlasBounds {155.5 176.5 174.5 207.5}} {advance 0.54545454545454541 planeBounds {0.033787288660706377 -0.041426927502876881 0.56348543861202083 0.76869965477560409} atlasBounds {132.5 90.5 149.5 116.5}} {advance 0.54545454545454541 planeBounds {0.0042418341152518444 -0.057006284854386136 0.5339399840665664 0.78427901212711337} atlasBounds {190.5 144.5 207.5 171.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403044 -0.041426927502876881 0.5687350624059484 0.76869965477560409} atlasBounds {188.5 117.5 207.5 143.5}} {advance 0.54545454545454541 planeBounds {0.023457555103124732 -0.047790563866513223 0.52199699035142078 0.76233601841196774} atlasBounds {77.5 90.5 93.5 116.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998938021 -0.041426927502876881 0.55315570505443923 0.76869965477560409} atlasBounds {58.5 90.5 76.5 116.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403051 -0.041426927502876881 0.5687350624059484 0.76869965477560409} atlasBounds {38.5 90.5 57.5 116.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998938082 -0.041426927502876881 0.55315570505443923 0.76869965477560409} atlasBounds {19.5 90.5 37.5 116.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403051 -0.041426927502876881 0.5687350624059484 0.76869965477560409} atlasBounds {94.5 90.5 113.5 116.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998937787 -0.041426927502876881 0.55315570505443923 0.76869965477560409} atlasBounds {0.5 90.5 18.5 116.5}} {advance 0.54545454545454541 planeBounds {0.10395680269097991 -0.16606178631495083 0.47786137912720195 0.89333451358767813} atlasBounds {81.5 173.5 93.5 207.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154556 -0.19709568912100559 0.53757634770292995 0.89345932548464191} atlasBounds {18.5 172.5 35.5 207.5}} {advance 0.54545454545454541 planeBounds {0.092138620872798102 -0.16606178631495083 0.46604319730902016 0.89333451358767813} atlasBounds {109.5 173.5 121.5 207.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154591 0.45953616004248915 0.53757634770292995 0.80228202177569274} atlasBounds {50.5 2.5 67.5 13.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403044 -0.20835133221209171 0.5687350624059484 -0.052557758696999198} atlasBounds {188.5 84.5 207.5 89.5}} {advance 0.54545454545454541 planeBounds {0.11738824466672569 0.51420642648490744 0.42897539169691074 0.82579357351509242} atlasBounds {68.5 3.5 78.5 13.5}} {advance 0.54545454545454541 planeBounds {0.01320793130919715 -0.046257413472603343 0.57406479596353022 0.60807559529078514} atlasBounds {180.5 41.5 198.5 62.5}} {advance 0.54545454545454541 planeBounds {0.033912100557670175 -0.047790563866513223 0.53245153580596627 0.76233601841196774} atlasBounds {45.5 117.5 61.5 143.5}} {advance 0.54545454545454541 planeBounds {0.02618482783039746 -0.046257413472603343 0.52472426307869346 0.60807559529078514} atlasBounds {144.5 41.5 160.5 62.5}} {advance 0.54545454545454541 planeBounds {0.019366646012215626 -0.047790563866513223 0.51790608126051163 0.76233601841196774} atlasBounds {8.5 117.5 24.5 143.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154851 -0.046257413472603343 0.53757634770293006 0.60807559529078514} atlasBounds {34.5 14.5 51.5 35.5}} {advance 0.54545454545454541 planeBounds {0.0045715676728334802 -0.035063291139240498 0.56542843232716644 0.77506329113924044} atlasBounds {185.5 90.5 203.5 116.5}} {advance 0.54545454545454541 planeBounds {0.015730282375851987 -0.22246083030893163 0.51426971762414797 0.61882446667256796} atlasBounds {173.5 144.5 189.5 171.5}} {advance 0.54545454545454541 planeBounds {0.033003009648579253 -0.041426927502876881 0.53154244489687519 0.76869965477560409} atlasBounds {119.5 63.5 135.5 89.5}} {advance 0.54545454545454541 planeBounds {0.062673276090997598 -0.044403824024077207 0.53005399663627506 0.82804018766044085} atlasBounds {175.5 179.5 190.5 207.5}} {advance 0.54545454545454541 planeBounds {0.025070815260688679 -0.21139151987253255 0.46129282110294767 0.81684606532707804} atlasBounds {122.5 174.5 136.5 207.5}} {advance 0.54545454545454541 planeBounds {0.055730282375851994 -0.041426927502876881 0.55426971762414801 0.76869965477560409} atlasBounds {91.5 36.5 107.5 62.5}} {advance 0.54545454545454541 planeBounds {0.063582367000088499 -0.047790563866513223 0.53096308754536603 0.76233601841196774} atlasBounds {75.5 36.5 90.5 62.5}} {advance 0.54545454545454541 planeBounds {-0.0077011595998937761 -0.039893777108967007 0.55315570505443934 0.61443923165442149} atlasBounds {161.5 41.5 179.5 62.5}} {advance 0.54545454545454541 planeBounds {0.028457555103124716 -0.039893777108967007 0.52699699035142067 0.61443923165442149} atlasBounds {0.5 14.5 16.5 35.5}} {advance 0.54545454545454541 planeBounds {0.023457555103124712 -0.046257413472603343 0.52199699035142066 0.60807559529078514} atlasBounds {90.5 14.5 106.5 35.5}} {advance 0.54545454545454541 planeBounds {0.029366646012215628 -0.20051783659378594 0.52790608126051164 0.60960874568469503} atlasBounds {101.5 117.5 117.5 143.5}} {advance 0.54545454545454541 planeBounds {0.017548464194033806 -0.20051783659378594 0.5160878994423298 0.60960874568469503} atlasBounds {171.5 117.5 187.5 143.5}} {advance 0.54545454545454541 planeBounds {0.062673276090997612 -0.039893777108967007 0.53005399663627517 0.61443923165442149} atlasBounds {158.5 14.5 173.5 35.5}} {advance 0.54545454545454541 planeBounds {0.030275736921306536 -0.046257413472603343 0.5288151721696025 0.60807559529078514} atlasBounds {17.5 14.5 33.5 35.5}} {advance 0.54545454545454541 planeBounds {0.0092418341152518246 -0.047790563866513223 0.53893998406656629 0.76233601841196774} atlasBounds {62.5 117.5 79.5 143.5}} {advance 0.54545454545454541 planeBounds {0.028457555103124716 -0.052621049836239733 0.52699699035142067 0.60171195892714879} atlasBounds {107.5 14.5 123.5 35.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154556 -0.046257413472603343 0.53757634770292995 0.60807559529078514} atlasBounds {140.5 14.5 157.5 35.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403006 -0.046257413472603343 0.56873506240594851 0.60807559529078514} atlasBounds {70.5 14.5 89.5 35.5}} {advance 0.54545454545454541 planeBounds {0.0078781977516154782 -0.046257413472603343 0.53757634770293006 0.60807559529078514} atlasBounds {52.5 14.5 69.5 35.5}} {advance 0.54545454545454541 planeBounds {-0.024644153315039417 -0.21324510932105867 0.56737142604231205 0.59688147295742233} atlasBounds {118.5 117.5 137.5 143.5}} {advance 0.54545454545454541 planeBounds {0.038582367000088505 -0.046257413472603343 0.50596308754536601 0.60807559529078514} atlasBounds {124.5 14.5 139.5 35.5}} {advance 0.54545454545454541 planeBounds {0.054616269806143224 -0.16606178631495083 0.49083827564840227 0.89333451358767813} atlasBounds {54.5 173.5 68.5 207.5}} {advance 0.54545454545454541 planeBounds {0.19483048596972649 -0.19709568912100559 0.35062405948481901 0.89345932548464191} atlasBounds {36.5 172.5 41.5 207.5}} {advance 0.54545454545454541 planeBounds {0.054616269806143224 -0.16606178631495083 0.49083827564840227 0.89333451358767813} atlasBounds {94.5 173.5 108.5 207.5}} {advance 0.54545454545454541 planeBounds {-0.023280516951403027 0.23900150482428961 0.5687350624059484 0.48827122244843768} atlasBounds {79.5 5.5 98.5 13.5}} {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}}} csv {32,0.54545454545454541,0,0,0,0,0,0,0,0
33,0.54545454545454541,0.16367177126670798,-0.047790563866513223,0.38178277418783751,0.76233601841196774,0.5,117.5,7.5,143.5
34,0.54545454545454541,0.070195627157652457,0.38622952996370719,0.47525891829689293,0.76013410639992918,20.5,1.5,33.5,13.5
35,0.54545454545454541,-0.023280516951403044,-0.041426927502876881,0.5687350624059484,0.76869965477560409,25.5,117.5,44.5,143.5
36,0.54545454545454541,0.0042418341152518444,-0.11705098698769585,0.5339399840665664,0.84886916880587771,137.5,176.5,154.5,207.5
37,0.54545454545454541,-0.038859874302912295,-0.04142692750287686,0.58431441975745768,0.76869965477560409,80.5,117.5,100.5,143.5
38,0.54545454545454541,-0.02646233513322124,-0.057006284854386136,0.56555324422413022,0.78427901212711337,0.5,144.5,19.5,171.5
39,0.54545454545454541,0.17925112861821724,0.38622952996370719,0.36620341683632823,0.76013410639992918,43.5,1.5,49.5,13.5
40,0.54545454545454541,0.10453616004248915,-0.16606178631495083,0.44728202177569265,0.89333451358767813,42.5,173.5,53.5,207.5
41,0.54545454545454541,0.098172523678852791,-0.16606178631495083,0.4409183854120563,0.89333451358767813,69.5,173.5,80.5,207.5
42,0.54545454545454541,-0.0077011595998937787,0.068083119412233314,0.55315570505443923,0.66009869876958482,174.5,16.5,192.5,35.5
43,0.54545454545454541,-0.023280516951403006,0.067628573957687899,0.56873506240594851,0.65964415331503945,188.5,64.5,207.5,83.5
44,0.54545454545454541,0.13400150482428963,-0.21740683367265645,0.38327122244843759,0.15649774276356557,34.5,1.5,42.5,13.5
45,0.54545454545454541,0.054616269806143224,0.28573957687881735,0.49083827564840227,0.44153315039390983,193.5,30.5,207.5,35.5
46,0.54545454545454541,0.16367177126670798,-0.056782774187837462,0.38178277418783751,0.16132822873329206,99.5,6.5,106.5,13.5
47,0.54545454545454541,0.0078781977516154556,-0.19709568912100559,0.53757634770292995,0.89345932548464191,0.5,172.5,17.5,207.5
48,0.54545454545454541,0.0078781977516154417,-0.057006284854386136,0.53757634770292995,0.78427901212711337,20.5,144.5,37.5,171.5
49,0.54545454545454541,0.045525360715234137,-0.041426927502876881,0.48174736655749317,0.76869965477560409,138.5,117.5,152.5,143.5
50,0.54545454545454541,0.0078024401758578932,-0.035063291139240498,0.53750059012717244,0.77506329113924044,153.5,117.5,170.5,143.5
51,0.54545454545454541,0.023457555103124729,-0.057006284854386136,0.52199699035142078,0.78427901212711337,191.5,180.5,207.5,207.5
52,0.54545454545454541,0.006514561387979111,-0.041426927502876881,0.53621271133929371,0.76869965477560409,114.5,90.5,131.5,116.5
53,0.54545454545454541,0.013332743206160949,-0.047790563866513223,0.54303089315747555,0.76233601841196774,150.5,90.5,167.5,116.5
54,0.54545454545454541,0.0078781977516154712,-0.057006284854386136,0.53757634770292995,0.78427901212711337,38.5,144.5,55.5,171.5
55,0.54545454545454541,0.0056054704788881726,-0.041426927502876881,0.53530362043020263,0.76869965477560409,57.5,36.5,74.5,62.5
56,0.54545454545454541,0.0078781977516154452,-0.057006284854386136,0.53757634770292995,0.78427901212711337,56.5,144.5,73.5,171.5
57,0.54545454545454541,0.0078781977516154712,-0.057006284854386136,0.53757634770292995,0.78427901212711337,74.5,144.5,91.5,171.5
58,0.54545454545454541,0.16367177126670798,-0.046711958927148821,0.38178277418783751,0.60762104983623966,199.5,41.5,206.5,62.5
59,0.54545454545454541,0.13400150482428963,-0.22291537576347703,0.38327122244843759,0.61836992121802248,92.5,144.5,100.5,171.5
60,0.54545454545454541,0.0069691068425245528,-0.010268212799858369,0.53666725679383898,0.73754094007258564,126.5,38.5,143.5,62.5
61,0.54545454545454541,-0.023280516951403006,0.17668407541825262,0.56873506240594851,0.55058865185447459,0.5,1.5,19.5,13.5
62,0.54545454545454541,0.0087872886607063706,-0.010268212799858369,0.53848543861202081,0.73754094007258564,108.5,38.5,125.5,62.5
63,0.54545454545454541,0.0078024401758578932,-0.057006284854386136,0.53750059012717244,0.78427901212711337,101.5,144.5,118.5,171.5
64,0.54545454545454541,-0.038859874302912309,-0.041426927502876895,0.58431441975745768,0.76869965477560409,17.5,36.5,37.5,62.5
65,0.54545454545454541,-0.0077011595998938021,-0.041426927502876881,0.55315570505443923,0.76869965477560409,38.5,36.5,56.5,62.5
66,0.54545454545454541,0.031639373284942894,-0.041426927502876881,0.53017880853323884,0.76869965477560409,0.5,36.5,16.5,62.5
67,0.54545454545454541,0.0087872886607063862,-0.057006284854386136,0.53848543861202092,0.78427901212711337,119.5,144.5,136.5,171.5
68,0.54545454545454541,0.0196963795697973,-0.041426927502876881,0.5493945295211119,0.76869965477560409,170.5,63.5,187.5,89.5
69,0.54545454545454541,0.036184827830397462,-0.041426927502876881,0.53472426307869347,0.76869965477560409,153.5,63.5,169.5,89.5
70,0.54545454545454541,0.03709391873948837,-0.041426927502876881,0.53563335398778444,0.76869965477560409,136.5,63.5,152.5,89.5
71,0.54545454545454541,0.013332743206160911,-0.057006284854386136,0.54303089315747544,0.78427901212711337,137.5,144.5,154.5,171.5
72,0.54545454545454541,0.023457555103124715,-0.041426927502876881,0.52199699035142066,0.76869965477560409,102.5,63.5,118.5,89.5
73,0.54545454545454541,0.054616269806143224,-0.041426927502876881,0.49083827564840227,0.76869965477560409,87.5,63.5,101.5,89.5
74,0.54545454545454541,-0.012121802248384529,-0.047790563866513223,0.51757634770292993,0.76233601841196774,69.5,63.5,86.5,89.5
75,0.54545454545454541,0.034241834115251828,-0.041426927502876881,0.56393998406656631,0.76869965477560409,51.5,63.5,68.5,89.5
76,0.54545454545454541,0.051309639727361231,-0.041426927502876881,0.51869036027263871,0.76869965477560409,35.5,63.5,50.5,89.5
77,0.54545454545454541,0.0078781977516154643,-0.041426927502876881,0.53757634770292995,0.76869965477560409,17.5,63.5,34.5,89.5
78,0.54545454545454541,0.023457555103124708,-0.041426927502876881,0.52199699035142066,0.76869965477560409,0.5,63.5,16.5,89.5
79,0.54545454545454541,0.0078781977516154417,-0.057006284854386136,0.53757634770292995,0.78427901212711337,155.5,144.5,172.5,171.5
80,0.54545454545454541,0.042093918739488347,-0.041426927502876881,0.54063335398778434,0.76869965477560409,168.5,90.5,184.5,116.5
81,0.54545454545454541,0.0049013012304151751,-0.18932371426042316,0.59691688058776671,0.77659644153315044,155.5,176.5,174.5,207.5
82,0.54545454545454541,0.033787288660706377,-0.041426927502876881,0.56348543861202083,0.76869965477560409,132.5,90.5,149.5,116.5
83,0.54545454545454541,0.0042418341152518444,-0.057006284854386136,0.5339399840665664,0.78427901212711337,190.5,144.5,207.5,171.5
84,0.54545454545454541,-0.023280516951403044,-0.041426927502876881,0.5687350624059484,0.76869965477560409,188.5,117.5,207.5,143.5
85,0.54545454545454541,0.023457555103124732,-0.047790563866513223,0.52199699035142078,0.76233601841196774,77.5,90.5,93.5,116.5
86,0.54545454545454541,-0.0077011595998938021,-0.041426927502876881,0.55315570505443923,0.76869965477560409,58.5,90.5,76.5,116.5
87,0.54545454545454541,-0.023280516951403051,-0.041426927502876881,0.5687350624059484,0.76869965477560409,38.5,90.5,57.5,116.5
88,0.54545454545454541,-0.0077011595998938082,-0.041426927502876881,0.55315570505443923,0.76869965477560409,19.5,90.5,37.5,116.5
89,0.54545454545454541,-0.023280516951403051,-0.041426927502876881,0.5687350624059484,0.76869965477560409,94.5,90.5,113.5,116.5
90,0.54545454545454541,-0.0077011595998937787,-0.041426927502876881,0.55315570505443923,0.76869965477560409,0.5,90.5,18.5,116.5
91,0.54545454545454541,0.10395680269097991,-0.16606178631495083,0.47786137912720195,0.89333451358767813,81.5,173.5,93.5,207.5
92,0.54545454545454541,0.0078781977516154556,-0.19709568912100559,0.53757634770292995,0.89345932548464191,18.5,172.5,35.5,207.5
93,0.54545454545454541,0.092138620872798102,-0.16606178631495083,0.46604319730902016,0.89333451358767813,109.5,173.5,121.5,207.5
94,0.54545454545454541,0.0078781977516154591,0.45953616004248915,0.53757634770292995,0.80228202177569274,50.5,2.5,67.5,13.5
95,0.54545454545454541,-0.023280516951403044,-0.20835133221209171,0.5687350624059484,-0.052557758696999198,188.5,84.5,207.5,89.5
96,0.54545454545454541,0.11738824466672569,0.51420642648490744,0.42897539169691074,0.82579357351509242,68.5,3.5,78.5,13.5
97,0.54545454545454541,0.01320793130919715,-0.046257413472603343,0.57406479596353022,0.60807559529078514,180.5,41.5,198.5,62.5
98,0.54545454545454541,0.033912100557670175,-0.047790563866513223,0.53245153580596627,0.76233601841196774,45.5,117.5,61.5,143.5
99,0.54545454545454541,0.02618482783039746,-0.046257413472603343,0.52472426307869346,0.60807559529078514,144.5,41.5,160.5,62.5
100,0.54545454545454541,0.019366646012215626,-0.047790563866513223,0.51790608126051163,0.76233601841196774,8.5,117.5,24.5,143.5
101,0.54545454545454541,0.0078781977516154851,-0.046257413472603343,0.53757634770293006,0.60807559529078514,34.5,14.5,51.5,35.5
102,0.54545454545454541,0.0045715676728334802,-0.035063291139240498,0.56542843232716644,0.77506329113924044,185.5,90.5,203.5,116.5
103,0.54545454545454541,0.015730282375851987,-0.22246083030893163,0.51426971762414797,0.61882446667256796,173.5,144.5,189.5,171.5
104,0.54545454545454541,0.033003009648579253,-0.041426927502876881,0.53154244489687519,0.76869965477560409,119.5,63.5,135.5,89.5
105,0.54545454545454541,0.062673276090997598,-0.044403824024077207,0.53005399663627506,0.82804018766044085,175.5,179.5,190.5,207.5
106,0.54545454545454541,0.025070815260688679,-0.21139151987253255,0.46129282110294767,0.81684606532707804,122.5,174.5,136.5,207.5
107,0.54545454545454541,0.055730282375851994,-0.041426927502876881,0.55426971762414801,0.76869965477560409,91.5,36.5,107.5,62.5
108,0.54545454545454541,0.063582367000088499,-0.047790563866513223,0.53096308754536603,0.76233601841196774,75.5,36.5,90.5,62.5
109,0.54545454545454541,-0.0077011595998937761,-0.039893777108967007,0.55315570505443934,0.61443923165442149,161.5,41.5,179.5,62.5
110,0.54545454545454541,0.028457555103124716,-0.039893777108967007,0.52699699035142067,0.61443923165442149,0.5,14.5,16.5,35.5
111,0.54545454545454541,0.023457555103124712,-0.046257413472603343,0.52199699035142066,0.60807559529078514,90.5,14.5,106.5,35.5
112,0.54545454545454541,0.029366646012215628,-0.20051783659378594,0.52790608126051164,0.60960874568469503,101.5,117.5,117.5,143.5
113,0.54545454545454541,0.017548464194033806,-0.20051783659378594,0.5160878994423298,0.60960874568469503,171.5,117.5,187.5,143.5
114,0.54545454545454541,0.062673276090997612,-0.039893777108967007,0.53005399663627517,0.61443923165442149,158.5,14.5,173.5,35.5
115,0.54545454545454541,0.030275736921306536,-0.046257413472603343,0.5288151721696025,0.60807559529078514,17.5,14.5,33.5,35.5
116,0.54545454545454541,0.0092418341152518246,-0.047790563866513223,0.53893998406656629,0.76233601841196774,62.5,117.5,79.5,143.5
117,0.54545454545454541,0.028457555103124716,-0.052621049836239733,0.52699699035142067,0.60171195892714879,107.5,14.5,123.5,35.5
118,0.54545454545454541,0.0078781977516154556,-0.046257413472603343,0.53757634770292995,0.60807559529078514,140.5,14.5,157.5,35.5
119,0.54545454545454541,-0.023280516951403006,-0.046257413472603343,0.56873506240594851,0.60807559529078514,70.5,14.5,89.5,35.5
120,0.54545454545454541,0.0078781977516154782,-0.046257413472603343,0.53757634770293006,0.60807559529078514,52.5,14.5,69.5,35.5
121,0.54545454545454541,-0.024644153315039417,-0.21324510932105867,0.56737142604231205,0.59688147295742233,118.5,117.5,137.5,143.5
122,0.54545454545454541,0.038582367000088505,-0.046257413472603343,0.50596308754536601,0.60807559529078514,124.5,14.5,139.5,35.5
123,0.54545454545454541,0.054616269806143224,-0.16606178631495083,0.49083827564840227,0.89333451358767813,54.5,173.5,68.5,207.5
124,0.54545454545454541,0.19483048596972649,-0.19709568912100559,0.35062405948481901,0.89345932548464191,36.5,172.5,41.5,207.5
125,0.54545454545454541,0.054616269806143224,-0.16606178631495083,0.49083827564840227,0.89333451358767813,94.5,173.5,108.5,207.5
126,0.54545454545454541,-0.023280516951403027,0.23900150482428961,0.5687350624059484,0.48827122244843768,79.5,5.5,98.5,13.5
} fields {} line {} values {} i 128 atlasBottom 5.5 planeBottom 0.23900150482428961 atlasTop 13.5 name VictorMonoRegular advance 0.54545454545454541 atlasRight 98.5 planeTop 0.48827122244843768 planeRight 0.5687350624059484 atlasLeft 79.5 planeLeft -0.023280516951403027 defaultGlyphInfo {advance 0.54545454545454541 planeBounds {0.0078024401758578932 -0.057006284854386136 0.53750059012717244 0.78427901212711337} atlasBounds {101.5 144.5 118.5 171.5}} im {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c298ac0}} csvFd ::aio.handle209}}
when the GPU has loaded image {width {200} height {200} components {3} bytesPerRow {600} uniq {0} dat (
[ m18011:0 (s23877:0) ]
)when the GPU has loaded image {width {200} height {200} components {3} bytesPerRow {600} uniq {0} data {(uint8_t*) 0x79d17c2f4430}} as texture /gim/ \n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {^loadImage {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} ^loadFont {name \n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ {builtin-programs/draw/text.folk 174}} glyphIdx {} glyphInfos {{advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 0.26700000000000002 planeBounds {0 0 0 0} atlasBounds {0 0 0 0}} {advance 0.30499999999999999 planeBounds {0.074249999999999997 -0.046625000000000014 0.26174999999999998 0.73462499999999997} atlasBounds {57.5 111.5 63.5 136.5}} {advance 0.33500000000000002 planeBounds {0.046875 0.46287500000000004 0.328125 0.74412500000000004} atlasBounds {53.5 2.5 62.5 11.5}} {advance 0.54500000000000004 planeBounds {-0.0081250000000000176 0.021874999999999981 0.52312500000000006 0.67812499999999998} atlasBounds {126.5 36.5 143.5 57.5}} {advance 0.54500000000000004 planeBounds {0.044625000000000012 -0.13437499999999999 0.51337500000000003 0.83437499999999998} atlasBounds {103.5 168.5 118.5 199.5}} {advance 0.77300000000000002 planeBounds {0.028500000000000018 -0.055750000000000015 0.77849999999999997 0.75675000000000003} atlasBounds {6.5 140.5 30.5 166.5}} {advance 0.81400000000000006 planeBounds {0.083750000000000005 -0.056250000000000015 0.77124999999999999 0.75624999999999998} atlasBounds {177.5 173.5 199.5 199.5}} {advance 0.218 planeBounds {0.05087500000000001 0.46287500000000004 0.207125 0.74412500000000004} atlasBounds {63.5 2.5 68.5 11.5}} {advance 0.28000000000000003 planeBounds {0.028375000000000015 -0.254 0.30962499999999998 0.746} atlasBounds {0.5 167.5 9.5 199.5}} {advance 0.28000000000000003 planeBounds {-0.029624999999999985 -0.254 0.25162499999999999 0.746} atlasBounds {10.5 167.5 19.5 199.5}} {advance 0.35100000000000003 planeBounds {0.0031250000000000106 0.41062500000000002 0.34687499999999999 0.75437500000000002} atlasBounds {0.5 0.5 11.5 11.5}} {advance 0.505 planeBounds {0.0019999999999999931 0.088499999999999995 0.502 0.58850000000000002} atlasBounds {173.5 15.5 189.5 31.5}} {advance 0.22500000000000001 planeBounds {-0.00037499999999999643 -0.18225 0.21837500000000001 0.13025} atlasBounds {45.5 1.5 52.5 11.5}} {advance 0.35999999999999999 planeBounds {0.023749999999999997 0.20987500000000001 0.33624999999999999 0.36612500000000003} atlasBounds {180.5 141.5 190.5 146.5}} {advance 0.214 planeBounds {0.013249999999999996 -0.047750000000000001 0.20075000000000001 0.13975000000000001} atlasBounds {173.5 140.5 179.5 146.5}} {advance 0.35399999999999998 planeBounds {-0.072999999999999995 -0.18275 0.42699999999999999 0.75475000000000003} atlasBounds {143.5 169.5 159.5 199.5}} {advance 0.54500000000000004 planeBounds {0.0068749999999999827 -0.056250000000000015 0.53812499999999996 0.75624999999999998} atlasBounds {31.5 140.5 48.5 166.5}} {advance 0.54500000000000004 planeBounds {0.032125000000000008 -0.034625000000000017 0.50087499999999996 0.74662499999999998} atlasBounds {112.5 111.5 127.5 136.5}} {advance 0.54500000000000004 planeBounds {0.02662500000000001 -0.034625000000000017 0.49537500000000001 0.74662499999999998} atlasBounds {128.5 111.5 143.5 136.5}} {advance 0.54500000000000004 planeBounds {0.045624999999999999 -0.046625000000000014 0.51437500000000003 0.73462499999999997} atlasBounds {144.5 111.5 159.5 136.5}} {advance 0.54500000000000004 planeBounds {-0.024875000000000001 -0.035125000000000017 0.56887500000000002 0.74612500000000004} atlasBounds {167.5 84.5 186.5 109.5}} {advance 0.54500000000000004 planeBounds {0.045749999999999999 -0.046625000000000014 0.48325000000000001 0.73462499999999997} atlasBounds {72.5 32.5 86.5 57.5}} {advance 0.54500000000000004 planeBounds {0.025999999999999995 -0.056250000000000015 0.52600000000000002 0.75624999999999998} atlasBounds {49.5 140.5 65.5 166.5}} {advance 0.54500000000000004 planeBounds {0.019999999999999993 -0.040624999999999967 0.52000000000000002 0.74062499999999998} atlasBounds {87.5 32.5 103.5 57.5}} {advance 0.54500000000000004 planeBounds {0.022500000000000013 -0.056250000000000015 0.52249999999999996 0.75624999999999998} atlasBounds {66.5 140.5 82.5 166.5}} {advance 0.54500000000000004 planeBounds {0.018499999999999999 -0.056250000000000015 0.51849999999999996 0.75624999999999998} atlasBounds {83.5 140.5 99.5 166.5}} {advance 0.219 planeBounds {0.05525 -0.049374999999999988 0.24274999999999999 0.54437500000000005} atlasBounds {85.5 12.5 91.5 31.5}} {advance 0.25600000000000001 planeBounds {0.039625 -0.18037500000000001 0.25837500000000002 0.53837500000000005} atlasBounds {118.5 34.5 125.5 57.5}} {advance 0.505 planeBounds {0.0024999999999999931 0.043249999999999997 0.50250000000000006 0.60575000000000001} atlasBounds {106.5 13.5 122.5 31.5}} {advance 0.505 planeBounds {0.0019999999999999931 0.18174999999999999 0.502 0.49425000000000002} atlasBounds {28.5 1.5 44.5 11.5}} {advance 0.505 planeBounds {0.0024999999999999931 0.043249999999999997 0.50250000000000006 0.60575000000000001} atlasBounds {123.5 13.5 139.5 31.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} {advance 1.0640000000000001 planeBounds {0.047625000000000008 -0.24399999999999999 1.016375 0.75600000000000001} atlasBounds {32.5 167.5 63.5 199.5}} {advance 0.58499999999999996 planeBounds {-0.035624999999999969 -0.035125000000000017 0.62062499999999998 0.74612500000000004} atlasBounds {178.5 111.5 199.5 136.5}} {advance 0.58399999999999996 planeBounds {0.040875000000000029 -0.040625000000000015 0.57212499999999999 0.74062499999999998} atlasBounds {0.5 32.5 17.5 57.5}} {advance 0.57100000000000006 planeBounds {0.013249999999999989 -0.056250000000000015 0.57574999999999998 0.75624999999999998} atlasBounds {115.5 140.5 133.5 166.5}} {advance 0.65400000000000003 planeBounds {0.044625000000000005 -0.041125000000000016 0.63837500000000003 0.74012500000000003} atlasBounds {168.5 58.5 187.5 83.5}} {advance 0.53600000000000003 planeBounds {0.043625000000000011 -0.040624999999999967 0.51237500000000002 0.74062499999999998} atlasBounds {152.5 58.5 167.5 83.5}} {advance 0.51700000000000002 planeBounds {0.041125000000000002 -0.040624999999999967 0.50987499999999997 0.74062499999999998} atlasBounds {136.5 58.5 151.5 83.5}} {advance 0.61199999999999999 planeBounds {0.024750000000000001 -0.056250000000000015 0.58725000000000005 0.75624999999999998} atlasBounds {134.5 140.5 152.5 166.5}} {advance 0.67200000000000004 planeBounds {0.039125 -0.040624999999999967 0.63287499999999997 0.74062499999999998} atlasBounds {109.5 58.5 128.5 83.5}} {advance 0.29099999999999998 planeBounds {0.067375000000000004 -0.040624999999999967 0.22362500000000002 0.74062499999999998} atlasBounds {103.5 58.5 108.5 83.5}} {advance 0.29099999999999998 planeBounds {-0.075749999999999998 -0.045625000000000013 0.23675000000000002 0.73562499999999997} atlasBounds {92.5 58.5 102.5 83.5}} {advance 0.60999999999999999 planeBounds {0.048750000000000002 -0.040624999999999967 0.61124999999999996 0.74062499999999998} atlasBounds {73.5 58.5 91.5 83.5}} {advance 0.51700000000000002 planeBounds {0.042000000000000016 -0.040624999999999967 0.54200000000000004 0.74062499999999998} atlasBounds {56.5 58.5 72.5 83.5}} {advance 0.79100000000000004 planeBounds {0.051750000000000004 -0.040624999999999967 0.73924999999999996 0.74062499999999998} atlasBounds {33.5 58.5 55.5 83.5}} {advance 0.67300000000000004 planeBounds {0.039625 -0.056250000000000015 0.63337500000000002 0.75624999999999998} atlasBounds {153.5 140.5 172.5 166.5}} {advance 0.68400000000000005 planeBounds {0.013875000000000031 -0.056250000000000015 0.67012499999999997 0.75624999999999998} atlasBounds {17.5 110.5 38.5 136.5}} {advance 0.55900000000000005 planeBounds {0.053499999999999999 -0.036625000000000012 0.55349999999999999 0.74462499999999998} atlasBounds {0.5 58.5 16.5 83.5}} {advance 0.68400000000000005 planeBounds {0.020625000000000011 -0.21987500000000001 0.739375 0.74887500000000007} atlasBounds {119.5 168.5 142.5 199.5}} {advance 0.59499999999999997 planeBounds {0.039249999999999986 -0.036625000000000012 0.60175000000000001 0.74462499999999998} atlasBounds {148.5 84.5 166.5 109.5}} {advance 0.53100000000000003 planeBounds {-0.00062499999999997161 -0.056250000000000015 0.53062500000000001 0.75624999999999998} atlasBounds {39.5 110.5 56.5 136.5}} {advance 0.55500000000000005 planeBounds {-0.019374999999999986 -0.040624999999999967 0.57437499999999997 0.74062499999999998} atlasBounds {111.5 84.5 130.5 109.5}} {advance 0.65200000000000002 planeBounds {0.044749999999999991 -0.045125000000000012 0.60725000000000007 0.73612500000000003} atlasBounds {92.5 84.5 110.5 109.5}} {advance 0.56800000000000006 planeBounds {-0.04412499999999997 -0.046125000000000013 0.61212500000000003 0.73512500000000003} atlasBounds {70.5 84.5 91.5 109.5}} {advance 0.82800000000000007 planeBounds {-0.023499999999999972 -0.046125000000000013 0.85150000000000003 0.73512500000000003} atlasBounds {41.5 84.5 69.5 109.5}} {advance 0.61799999999999999 planeBounds {-0.020624999999999973 -0.040624999999999967 0.635625 0.74062499999999998} atlasBounds {19.5 84.5 40.5 109.5}} {advance 0.55800000000000005 planeBounds {-0.032999999999999981 -0.040624999999999967 0.59199999999999997 0.74062499999999998} atlasBounds {18.5 32.5 38.5 57.5}} {advance 0.54500000000000004 planeBounds {-0.0082500000000000143 -0.040624999999999967 0.55425000000000002 0.74062499999999998} atlasBounds {0.5 84.5 18.5 109.5}} {advance 0.30399999999999999 planeBounds {0.050500000000000003 -0.26500000000000001 0.30049999999999999 0.73499999999999999} atlasBounds {76.5 167.5 84.5 199.5}} {advance 0.38 planeBounds {-0.069000000000000006 -0.18275 0.43099999999999999 0.75475000000000003} atlasBounds {160.5 169.5 176.5 199.5}} {advance 0.30399999999999999 planeBounds {0.0039999999999999966 -0.26500000000000001 0.254 0.73499999999999999} atlasBounds {85.5 167.5 93.5 199.5}} {advance 0.5 planeBounds {0.0056250000000000033 0.40112500000000001 0.47437499999999999 0.74487500000000006} atlasBounds {12.5 0.5 27.5 11.5}} {advance 0.40800000000000003 planeBounds {-0.045999999999999985 -0.24812500000000001 0.45400000000000001 -0.091874999999999998} atlasBounds {87.5 6.5 103.5 11.5}} {advance 0.28000000000000003 planeBounds {0.015000000000000005 0.53612499999999996 0.26500000000000001 0.75487499999999996} atlasBounds {190.5 24.5 198.5 31.5}} {advance 0.496 planeBounds {0.0001250000000000071 -0.046874999999999993 0.46887499999999999 0.546875} atlasBounds {144.5 38.5 159.5 57.5}} {advance 0.54000000000000004 planeBounds {0.034000000000000016 -0.045125000000000012 0.53400000000000003 0.73612500000000003} atlasBounds {131.5 84.5 147.5 109.5}} {advance 0.45100000000000001 planeBounds {0.014749999999999997 -0.046874999999999986 0.45224999999999999 0.546875} atlasBounds {185.5 38.5 199.5 57.5}} {advance 0.53800000000000003 planeBounds {0.0099999999999999933 -0.046625000000000014 0.51000000000000001 0.73462499999999997} atlasBounds {39.5 32.5 55.5 57.5}} {advance 0.50800000000000001 planeBounds {0.0040000000000000174 -0.046874999999999986 0.504 0.546875} atlasBounds {50.5 12.5 66.5 31.5}} {advance 0.31900000000000001 planeBounds {-0.016624999999999994 -0.037625000000000013 0.389625 0.74362499999999998} atlasBounds {98.5 111.5 111.5 136.5}} {advance 0.53700000000000003 planeBounds {0.0045000000000000179 -0.25774999999999998 0.50450000000000006 0.55474999999999997} atlasBounds {0.5 110.5 16.5 136.5}} {advance 0.54700000000000004 planeBounds {0.043125000000000017 -0.040624999999999967 0.51187499999999997 0.74062499999999998} atlasBounds {17.5 58.5 32.5 83.5}} {advance 0.26800000000000002 planeBounds {0.039750000000000014 -0.036625000000000012 0.22725000000000001 0.74462499999999998} atlasBounds {129.5 58.5 135.5 83.5}} {advance 0.26700000000000002 planeBounds {-0.026000000000000002 -0.252 0.224 0.748} atlasBounds {94.5 167.5 102.5 199.5}} {advance 0.47900000000000004 planeBounds {0.038625000000000007 -0.040624999999999967 0.50737500000000002 0.74062499999999998} atlasBounds {56.5 32.5 71.5 57.5}} {advance 0.29199999999999998 planeBounds {0.043875000000000004 -0.046625000000000014 0.325125 0.73462499999999997} atlasBounds {187.5 84.5 196.5 109.5}} {advance 0.81200000000000006 planeBounds {0.035000000000000017 -0.040874999999999995 0.78500000000000003 0.55287500000000001} atlasBounds {160.5 38.5 184.5 57.5}} {advance 0.54700000000000004 planeBounds {0.043125000000000017 -0.040874999999999995 0.51187499999999997 0.55287500000000001} atlasBounds {0.5 12.5 15.5 31.5}} {advance 0.53600000000000003 planeBounds {0.0023750000000000286 -0.046874999999999986 0.53362500000000002 0.546875} atlasBounds {67.5 12.5 84.5 31.5}} {advance 0.54100000000000004 planeBounds {0.034500000000000017 -0.23462500000000003 0.53449999999999998 0.54662500000000003} atlasBounds {64.5 111.5 80.5 136.5}} {advance 0.53700000000000003 planeBounds {0.0045000000000000179 -0.23612500000000003 0.50450000000000006 0.54512499999999997} atlasBounds {81.5 111.5 97.5 136.5}} {advance 0.34000000000000002 planeBounds {0.031625000000000007 -0.041875000000000002 0.37537500000000001 0.551875} atlasBounds {188.5 64.5 199.5 83.5}} {advance 0.42099999999999999 planeBounds {0.0048750000000000104 -0.046874999999999986 0.41112500000000002 0.546875} atlasBounds {92.5 12.5 105.5 31.5}} {advance 0.33900000000000002 planeBounds {-0.033625000000000002 -0.054375 0.37262499999999998 0.66437500000000005} atlasBounds {104.5 34.5 117.5 57.5}} {advance 0.53900000000000003 planeBounds {0.036625000000000012 -0.052874999999999998 0.50537500000000002 0.54087499999999999} atlasBounds {34.5 12.5 49.5 31.5}} {advance 0.48199999999999998 planeBounds {-0.024625000000000015 -0.052374999999999998 0.50662499999999999 0.54137500000000005} atlasBounds {16.5 12.5 33.5 31.5}} {advance 0.73499999999999999 planeBounds {-0.038750000000000014 -0.052374999999999998 0.77375000000000005 0.54137500000000005} atlasBounds {173.5 147.5 199.5 166.5}} {advance 0.51500000000000001 planeBounds {-0.0081250000000000176 -0.03125 0.52312500000000006 0.53125} atlasBounds {140.5 13.5 157.5 31.5}} {advance 0.46600000000000003 planeBounds {-0.031124999999999972 -0.24312499999999995 0.50012500000000004 0.53812499999999996} atlasBounds {160.5 111.5 177.5 136.5}} {advance 0.44700000000000001 planeBounds {0.0012499999999999929 -0.03125 0.43875000000000003 0.53125} atlasBounds {158.5 13.5 172.5 31.5}} {advance 0.34600000000000003 planeBounds {0.015125000000000003 -0.26450000000000001 0.358875 0.73550000000000004} atlasBounds {64.5 167.5 75.5 199.5}} {advance 0.23800000000000002 planeBounds {0.040875000000000002 -0.16812499999999997 0.19712499999999999 0.73812500000000003} atlasBounds {0.5 137.5 5.5 166.5}} {advance 0.34600000000000003 planeBounds {0.013125000000000003 -0.26450000000000001 0.356875 0.73550000000000004} atlasBounds {20.5 167.5 31.5 199.5}} {advance 0.505 planeBounds {-0.013124999999999968 0.24712500000000001 0.51812500000000006 0.46587499999999998} atlasBounds {69.5 4.5 86.5 11.5}} {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}}} csv {32,0.26700000000000002,0,0,0,0,0,0,0,0
33,0.30499999999999999,0.074249999999999997,-0.046625000000000014,0.26174999999999998,0.73462499999999997,57.5,111.5,63.5,136.5
34,0.33500000000000002,0.046875,0.46287500000000004,0.328125,0.74412500000000004,53.5,2.5,62.5,11.5
35,0.54500000000000004,-0.0081250000000000176,0.021874999999999981,0.52312500000000006,0.67812499999999998,126.5,36.5,143.5,57.5
36,0.54500000000000004,0.044625000000000012,-0.13437499999999999,0.51337500000000003,0.83437499999999998,103.5,168.5,118.5,199.5
37,0.77300000000000002,0.028500000000000018,-0.055750000000000015,0.77849999999999997,0.75675000000000003,6.5,140.5,30.5,166.5
38,0.81400000000000006,0.083750000000000005,-0.056250000000000015,0.77124999999999999,0.75624999999999998,177.5,173.5,199.5,199.5
39,0.218,0.05087500000000001,0.46287500000000004,0.207125,0.74412500000000004,63.5,2.5,68.5,11.5
40,0.28000000000000003,0.028375000000000015,-0.254,0.30962499999999998,0.746,0.5,167.5,9.5,199.5
41,0.28000000000000003,-0.029624999999999985,-0.254,0.25162499999999999,0.746,10.5,167.5,19.5,199.5
42,0.35100000000000003,0.0031250000000000106,0.41062500000000002,0.34687499999999999,0.75437500000000002,0.5,0.5,11.5,11.5
43,0.505,0.0019999999999999931,0.088499999999999995,0.502,0.58850000000000002,173.5,15.5,189.5,31.5
44,0.22500000000000001,-0.00037499999999999643,-0.18225,0.21837500000000001,0.13025,45.5,1.5,52.5,11.5
45,0.35999999999999999,0.023749999999999997,0.20987500000000001,0.33624999999999999,0.36612500000000003,180.5,141.5,190.5,146.5
46,0.214,0.013249999999999996,-0.047750000000000001,0.20075000000000001,0.13975000000000001,173.5,140.5,179.5,146.5
47,0.35399999999999998,-0.072999999999999995,-0.18275,0.42699999999999999,0.75475000000000003,143.5,169.5,159.5,199.5
48,0.54500000000000004,0.0068749999999999827,-0.056250000000000015,0.53812499999999996,0.75624999999999998,31.5,140.5,48.5,166.5
49,0.54500000000000004,0.032125000000000008,-0.034625000000000017,0.50087499999999996,0.74662499999999998,112.5,111.5,127.5,136.5
50,0.54500000000000004,0.02662500000000001,-0.034625000000000017,0.49537500000000001,0.74662499999999998,128.5,111.5,143.5,136.5
51,0.54500000000000004,0.045624999999999999,-0.046625000000000014,0.51437500000000003,0.73462499999999997,144.5,111.5,159.5,136.5
52,0.54500000000000004,-0.024875000000000001,-0.035125000000000017,0.56887500000000002,0.74612500000000004,167.5,84.5,186.5,109.5
53,0.54500000000000004,0.045749999999999999,-0.046625000000000014,0.48325000000000001,0.73462499999999997,72.5,32.5,86.5,57.5
54,0.54500000000000004,0.025999999999999995,-0.056250000000000015,0.52600000000000002,0.75624999999999998,49.5,140.5,65.5,166.5
55,0.54500000000000004,0.019999999999999993,-0.040624999999999967,0.52000000000000002,0.74062499999999998,87.5,32.5,103.5,57.5
56,0.54500000000000004,0.022500000000000013,-0.056250000000000015,0.52249999999999996,0.75624999999999998,66.5,140.5,82.5,166.5
57,0.54500000000000004,0.018499999999999999,-0.056250000000000015,0.51849999999999996,0.75624999999999998,83.5,140.5,99.5,166.5
58,0.219,0.05525,-0.049374999999999988,0.24274999999999999,0.54437500000000005,85.5,12.5,91.5,31.5
59,0.25600000000000001,0.039625,-0.18037500000000001,0.25837500000000002,0.53837500000000005,118.5,34.5,125.5,57.5
60,0.505,0.0024999999999999931,0.043249999999999997,0.50250000000000006,0.60575000000000001,106.5,13.5,122.5,31.5
61,0.505,0.0019999999999999931,0.18174999999999999,0.502,0.49425000000000002,28.5,1.5,44.5,11.5
62,0.505,0.0024999999999999931,0.043249999999999997,0.50250000000000006,0.60575000000000001,123.5,13.5,139.5,31.5
63,0.436,-0.00075000000000000359,-0.056250000000000015,0.43675000000000003,0.75624999999999998,100.5,140.5,114.5,166.5
64,1.0640000000000001,0.047625000000000008,-0.24399999999999999,1.016375,0.75600000000000001,32.5,167.5,63.5,199.5
65,0.58499999999999996,-0.035624999999999969,-0.035125000000000017,0.62062499999999998,0.74612500000000004,178.5,111.5,199.5,136.5
66,0.58399999999999996,0.040875000000000029,-0.040625000000000015,0.57212499999999999,0.74062499999999998,0.5,32.5,17.5,57.5
67,0.57100000000000006,0.013249999999999989,-0.056250000000000015,0.57574999999999998,0.75624999999999998,115.5,140.5,133.5,166.5
68,0.65400000000000003,0.044625000000000005,-0.041125000000000016,0.63837500000000003,0.74012500000000003,168.5,58.5,187.5,83.5
69,0.53600000000000003,0.043625000000000011,-0.040624999999999967,0.51237500000000002,0.74062499999999998,152.5,58.5,167.5,83.5
70,0.51700000000000002,0.041125000000000002,-0.040624999999999967,0.50987499999999997,0.74062499999999998,136.5,58.5,151.5,83.5
71,0.61199999999999999,0.024750000000000001,-0.056250000000000015,0.58725000000000005,0.75624999999999998,134.5,140.5,152.5,166.5
72,0.67200000000000004,0.039125,-0.040624999999999967,0.63287499999999997,0.74062499999999998,109.5,58.5,128.5,83.5
73,0.29099999999999998,0.067375000000000004,-0.040624999999999967,0.22362500000000002,0.74062499999999998,103.5,58.5,108.5,83.5
74,0.29099999999999998,-0.075749999999999998,-0.045625000000000013,0.23675000000000002,0.73562499999999997,92.5,58.5,102.5,83.5
75,0.60999999999999999,0.048750000000000002,-0.040624999999999967,0.61124999999999996,0.74062499999999998,73.5,58.5,91.5,83.5
76,0.51700000000000002,0.042000000000000016,-0.040624999999999967,0.54200000000000004,0.74062499999999998,56.5,58.5,72.5,83.5
77,0.79100000000000004,0.051750000000000004,-0.040624999999999967,0.73924999999999996,0.74062499999999998,33.5,58.5,55.5,83.5
78,0.67300000000000004,0.039625,-0.056250000000000015,0.63337500000000002,0.75624999999999998,153.5,140.5,172.5,166.5
79,0.68400000000000005,0.013875000000000031,-0.056250000000000015,0.67012499999999997,0.75624999999999998,17.5,110.5,38.5,136.5
80,0.55900000000000005,0.053499999999999999,-0.036625000000000012,0.55349999999999999,0.74462499999999998,0.5,58.5,16.5,83.5
81,0.68400000000000005,0.020625000000000011,-0.21987500000000001,0.739375,0.74887500000000007,119.5,168.5,142.5,199.5
82,0.59499999999999997,0.039249999999999986,-0.036625000000000012,0.60175000000000001,0.74462499999999998,148.5,84.5,166.5,109.5
83,0.53100000000000003,-0.00062499999999997161,-0.056250000000000015,0.53062500000000001,0.75624999999999998,39.5,110.5,56.5,136.5
84,0.55500000000000005,-0.019374999999999986,-0.040624999999999967,0.57437499999999997,0.74062499999999998,111.5,84.5,130.5,109.5
85,0.65200000000000002,0.044749999999999991,-0.045125000000000012,0.60725000000000007,0.73612500000000003,92.5,84.5,110.5,109.5
86,0.56800000000000006,-0.04412499999999997,-0.046125000000000013,0.61212500000000003,0.73512500000000003,70.5,84.5,91.5,109.5
87,0.82800000000000007,-0.023499999999999972,-0.046125000000000013,0.85150000000000003,0.73512500000000003,41.5,84.5,69.5,109.5
88,0.61799999999999999,-0.020624999999999973,-0.040624999999999967,0.635625,0.74062499999999998,19.5,84.5,40.5,109.5
89,0.55800000000000005,-0.032999999999999981,-0.040624999999999967,0.59199999999999997,0.74062499999999998,18.5,32.5,38.5,57.5
90,0.54500000000000004,-0.0082500000000000143,-0.040624999999999967,0.55425000000000002,0.74062499999999998,0.5,84.5,18.5,109.5
91,0.30399999999999999,0.050500000000000003,-0.26500000000000001,0.30049999999999999,0.73499999999999999,76.5,167.5,84.5,199.5
92,0.38,-0.069000000000000006,-0.18275,0.43099999999999999,0.75475000000000003,160.5,169.5,176.5,199.5
93,0.30399999999999999,0.0039999999999999966,-0.26500000000000001,0.254,0.73499999999999999,85.5,167.5,93.5,199.5
94,0.5,0.0056250000000000033,0.40112500000000001,0.47437499999999999,0.74487500000000006,12.5,0.5,27.5,11.5
95,0.40800000000000003,-0.045999999999999985,-0.24812500000000001,0.45400000000000001,-0.091874999999999998,87.5,6.5,103.5,11.5
96,0.28000000000000003,0.015000000000000005,0.53612499999999996,0.26500000000000001,0.75487499999999996,190.5,24.5,198.5,31.5
97,0.496,0.0001250000000000071,-0.046874999999999993,0.46887499999999999,0.546875,144.5,38.5,159.5,57.5
98,0.54000000000000004,0.034000000000000016,-0.045125000000000012,0.53400000000000003,0.73612500000000003,131.5,84.5,147.5,109.5
99,0.45100000000000001,0.014749999999999997,-0.046874999999999986,0.45224999999999999,0.546875,185.5,38.5,199.5,57.5
100,0.53800000000000003,0.0099999999999999933,-0.046625000000000014,0.51000000000000001,0.73462499999999997,39.5,32.5,55.5,57.5
101,0.50800000000000001,0.0040000000000000174,-0.046874999999999986,0.504,0.546875,50.5,12.5,66.5,31.5
102,0.31900000000000001,-0.016624999999999994,-0.037625000000000013,0.389625,0.74362499999999998,98.5,111.5,111.5,136.5
103,0.53700000000000003,0.0045000000000000179,-0.25774999999999998,0.50450000000000006,0.55474999999999997,0.5,110.5,16.5,136.5
104,0.54700000000000004,0.043125000000000017,-0.040624999999999967,0.51187499999999997,0.74062499999999998,17.5,58.5,32.5,83.5
105,0.26800000000000002,0.039750000000000014,-0.036625000000000012,0.22725000000000001,0.74462499999999998,129.5,58.5,135.5,83.5
106,0.26700000000000002,-0.026000000000000002,-0.252,0.224,0.748,94.5,167.5,102.5,199.5
107,0.47900000000000004,0.038625000000000007,-0.040624999999999967,0.50737500000000002,0.74062499999999998,56.5,32.5,71.5,57.5
108,0.29199999999999998,0.043875000000000004,-0.046625000000000014,0.325125,0.73462499999999997,187.5,84.5,196.5,109.5
109,0.81200000000000006,0.035000000000000017,-0.040874999999999995,0.78500000000000003,0.55287500000000001,160.5,38.5,184.5,57.5
110,0.54700000000000004,0.043125000000000017,-0.040874999999999995,0.51187499999999997,0.55287500000000001,0.5,12.5,15.5,31.5
111,0.53600000000000003,0.0023750000000000286,-0.046874999999999986,0.53362500000000002,0.546875,67.5,12.5,84.5,31.5
112,0.54100000000000004,0.034500000000000017,-0.23462500000000003,0.53449999999999998,0.54662500000000003,64.5,111.5,80.5,136.5
113,0.53700000000000003,0.0045000000000000179,-0.23612500000000003,0.50450000000000006,0.54512499999999997,81.5,111.5,97.5,136.5
114,0.34000000000000002,0.031625000000000007,-0.041875000000000002,0.37537500000000001,0.551875,188.5,64.5,199.5,83.5
115,0.42099999999999999,0.0048750000000000104,-0.046874999999999986,0.41112500000000002,0.546875,92.5,12.5,105.5,31.5
116,0.33900000000000002,-0.033625000000000002,-0.054375,0.37262499999999998,0.66437500000000005,104.5,34.5,117.5,57.5
117,0.53900000000000003,0.036625000000000012,-0.052874999999999998,0.50537500000000002,0.54087499999999999,34.5,12.5,49.5,31.5
118,0.48199999999999998,-0.024625000000000015,-0.052374999999999998,0.50662499999999999,0.54137500000000005,16.5,12.5,33.5,31.5
119,0.73499999999999999,-0.038750000000000014,-0.052374999999999998,0.77375000000000005,0.54137500000000005,173.5,147.5,199.5,166.5
120,0.51500000000000001,-0.0081250000000000176,-0.03125,0.52312500000000006,0.53125,140.5,13.5,157.5,31.5
121,0.46600000000000003,-0.031124999999999972,-0.24312499999999995,0.50012500000000004,0.53812499999999996,160.5,111.5,177.5,136.5
122,0.44700000000000001,0.0012499999999999929,-0.03125,0.43875000000000003,0.53125,158.5,13.5,172.5,31.5
123,0.34600000000000003,0.015125000000000003,-0.26450000000000001,0.358875,0.73550000000000004,64.5,167.5,75.5,199.5
124,0.23800000000000002,0.040875000000000002,-0.16812499999999997,0.19712499999999999,0.73812500000000003,0.5,137.5,5.5,166.5
125,0.34600000000000003,0.013125000000000003,-0.26450000000000001,0.356875,0.73550000000000004,20.5,167.5,31.5,199.5
126,0.505,-0.013124999999999968,0.24712500000000001,0.51812500000000006,0.46587499999999998,69.5,4.5,86.5,11.5
} fields {} line {} values {} i 128 atlasBottom 4.5 planeBottom 0.24712500000000001 atlasTop 11.5 name PTSans-Regular advance 0.505 atlasRight 86.5 planeTop 0.46587499999999998 planeRight 0.51812500000000006 atlasLeft 69.5 planeLeft -0.013124999999999968 defaultGlyphInfo {advance 0.436 planeBounds {-0.00075000000000000359 -0.056250000000000015 0.43675000000000003 0.75624999999999998} atlasBounds {100.5 140.5 114.5 166.5}} im {width {200} height {200} components {3} bytesPerRow {600} uniq {0} data {(uint8_t*) 0x79d17c2f4430}} csvFd ::aio.handle210}}
when the GPU has loaded image {width {192} height {192} components {3} bytesPerRow {576} uniq {0} dat (
[ m18010:0 (s23876:0) ]
)when the GPU has loaded image {width {192} height {192} components {3} bytesPerRow {576} uniq {0} data {(uint8_t*) 0x79d17c42a090}} as texture /gim/ \n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {^loadImage {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} ^loadFont {name \n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ {builtin-programs/draw/text.folk 174}} glyphIdx {} glyphInfos {{advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {0 0 0 0} atlasBounds {0 0 0 0}} {advance 0.599609375 planeBounds {0.20651022685860057 -0.050255718917031039 0.3930991481413994 0.66500181266703107} atlasBounds {125.5 137.5 131.5 160.5}} {advance 0.599609375 planeBounds {0.08463732817714352 0.31333515549076779 0.52001147783700741 0.65541484450923226} atlasBounds {129.5 13.5 143.5 24.5}} {advance 0.599609375 planeBounds {-0.011176847971331333 -0.052284767143464472 0.61078622297133145 0.63187461089346453} atlasBounds {51.5 113.5 71.5 135.5}} {advance 0.599609375 planeBounds {0.050531177872934915 -0.1455792277848639 0.54810163462706507 0.72516907153486398} atlasBounds {135.5 163.5 151.5 191.5}} {advance 0.599609375 planeBounds {-0.011176847971331333 -0.052284767143464472 0.61078622297133145 0.63187461089346453} atlasBounds {91.5 113.5 111.5 135.5}} {advance 0.599609375 planeBounds {0.040597335474368376 -0.053185406417031039 0.56926594577563172 0.66207212516703107} atlasBounds {0.5 112.5 17.5 135.5}} {advance 0.599609375 planeBounds {0.20658853611567607 0.31333515549076779 0.39317745739847487 0.65541484450923226} atlasBounds {184.5 92.5 190.5 103.5}} {advance 0.599609375 planeBounds {0.11265156174076774 -0.21305433445699704 0.45473125075923226 0.71989027195699706} atlasBounds {0.5 161.5 11.5 191.5}} {advance 0.599609375 planeBounds {0.14487812424076774 -0.21305433445699704 0.48695781325923226 0.71989027195699706} atlasBounds {12.5 161.5 23.5 191.5}} {advance 0.599609375 planeBounds {0.019921305575801802 0.030663493075801809 0.57968806942419826 0.59043025692419826} atlasBounds {160.5 25.5 178.5 43.5}} {advance 0.599609375 planeBounds {0.051019459122934915 0.035394459122934922 0.54858991587706507 0.53296491587706507} atlasBounds {88.5 8.5 104.5 24.5}} {advance 0.599609375 planeBounds {0.14928902643646744 -0.18658892128279883 0.39807425481353254 0.18658892128279883} atlasBounds {120.5 12.5 128.5 24.5}} {advance 0.599609375 planeBounds {0.051019459122934915 0.20643430363216717 0.54858991587706507 0.36192507136783286} atlasBounds {21.5 0.5 37.5 5.5}} {advance 0.599609375 planeBounds {0.19096115008503403 -0.038042756164965982 0.408648224914966 0.17964431866496597} atlasBounds {184.5 104.5 191.5 111.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.21281019383199704 0.54858991587706507 0.72013441258199706} atlasBounds {24.5 161.5 40.5 191.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.052284767143464472 0.54858991587706507 0.63187461089346453} atlasBounds {112.5 113.5 128.5 135.5}} {advance 0.599609375 planeBounds {0.073648614021501496 -0.046181251518464472 0.54012091722849853 0.63797812651846453} atlasBounds {129.5 113.5 144.5 135.5}} {advance 0.599609375 planeBounds {0.063150567146501496 -0.031364596619897905 0.52962287035349853 0.62169662786989799} atlasBounds {69.5 44.5 84.5 65.5}} {advance 0.599609375 planeBounds {0.054605645271501489 -0.052284767143464472 0.52107794847849853 0.63187461089346453} atlasBounds {145.5 113.5 160.5 135.5}} {advance 0.599609375 planeBounds {0.030587569849368376 -0.049355079643464472 0.55925618015063172 0.63480429839346453} atlasBounds {161.5 113.5 178.5 135.5}} {advance 0.599609375 planeBounds {0.058756035896501489 -0.042106784119897905 0.52522833910349853 0.61095444036989799} atlasBounds {101.5 44.5 116.5 65.5}} {advance 0.599609375 planeBounds {0.053216724747934915 -0.052272560112214539 0.55078718150206507 0.63188681792471446} atlasBounds {0.5 89.5 16.5 111.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.042106784119897905 0.54858991587706507 0.61095444036989799} atlasBounds {117.5 44.5 133.5 65.5}} {advance 0.599609375 planeBounds {0.066568535896501496 -0.052284767143464472 0.53304083910349853 0.63187461089346453} atlasBounds {17.5 89.5 32.5 111.5}} {advance 0.599609375 planeBounds {0.048822193497934915 -0.052296974174714489 0.54639265025206507 0.63186240386221448} atlasBounds {33.5 89.5 49.5 111.5}} {advance 0.599609375 planeBounds {0.19096115008503403 -0.038748367650631679 0.408648224914966 0.48992024265063167} atlasBounds {179.5 26.5 186.5 43.5}} {advance 0.599609375 planeBounds {0.15905465143646744 -0.18582968901846453 0.40783987981353254 0.49832968901846447} atlasBounds {179.5 113.5 187.5 135.5}} {advance 0.599609375 planeBounds {0.023263351099368376 0.020333663599368376 0.55193196140063172 0.54900227390063172} atlasBounds {34.5 7.5 51.5 24.5}} {advance 0.599609375 planeBounds {0.051019459122934915 0.11313984299076774 0.54858991587706507 0.45521953200923226} atlasBounds {144.5 13.5 160.5 24.5}} {advance 0.599609375 planeBounds {0.047677413599368376 0.020333663599368376 0.57634602390063172 0.54900227390063172} atlasBounds {52.5 7.5 69.5 24.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} {advance 0.599609375 planeBounds {-0.013129972971331333 -0.11624961089346447 0.60883309797133145 0.56790976714346453} atlasBounds {145.5 89.5 165.5 111.5}} {advance 0.599609375 planeBounds {0.0033956663022352371 -0.049355079643464472 0.5942605836977648 0.63480429839346453} atlasBounds {172.5 169.5 191.5 191.5}} {advance 0.599609375 planeBounds {0.063470630997934915 -0.036735690369897905 0.56104108775206507 0.61632553411989799} atlasBounds {52.5 44.5 68.5 65.5}} {advance 0.599609375 planeBounds {0.034493819849368376 -0.052284767143464472 0.56316243015063172 0.63187461089346453} atlasBounds {0.5 66.5 17.5 88.5}} {advance 0.599609375 planeBounds {0.046944991724368376 -0.036735690369897905 0.57561360202563172 0.61632553411989799} atlasBounds {16.5 44.5 33.5 65.5}} {advance 0.599609375 planeBounds {0.075601739021501496 -0.036735690369897905 0.54207404222849853 0.61632553411989799} atlasBounds {134.5 44.5 149.5 65.5}} {advance 0.599609375 planeBounds {0.080484551521501496 -0.039177096619897905 0.54695685472849853 0.61388412786989799} atlasBounds {0.5 44.5 15.5 65.5}} {advance 0.599609375 planeBounds {0.011376383700801804 -0.052284767143464472 0.57114314754919826 0.63187461089346453} atlasBounds {55.5 66.5 73.5 88.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.036735690369897905 0.54858991587706507 0.61632553411989799} atlasBounds {141.5 67.5 157.5 88.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.036735690369897905 0.54858991587706507 0.61632553411989799} atlasBounds {124.5 67.5 140.5 88.5}} {advance 0.599609375 planeBounds {0.044595879646501461 -0.042106784119897905 0.51106818285349853 0.61095444036989799} atlasBounds {108.5 67.5 123.5 88.5}} {advance 0.599609375 planeBounds {0.071038990372934915 -0.051796485893464472 0.56860944712706507 0.63236289214346453} atlasBounds {74.5 66.5 90.5 88.5}} {advance 0.599609375 planeBounds {0.080484551521501496 -0.034294284119897905 0.54695685472849853 0.61876694036989799} atlasBounds {158.5 67.5 173.5 88.5}} {advance 0.599609375 planeBounds {0.035469584504188571 -0.036735690369897905 0.56413819480545191 0.61632553411989799} atlasBounds {34.5 44.5 51.5 65.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.055214454643464472 0.54858991587706507 0.62894492339346453} atlasBounds {38.5 66.5 54.5 88.5}} {advance 0.599609375 planeBounds {0.0043722288022352371 -0.052284767143464472 0.5952371461977648 0.63187461089346453} atlasBounds {18.5 66.5 37.5 88.5}} {advance 0.599609375 planeBounds {0.070306568497934915 -0.039177096619897905 0.56787702525206507 0.61388412786989799} atlasBounds {91.5 67.5 107.5 88.5}} {advance 0.599609375 planeBounds {0.0043722288022352371 -0.11902745194059761 0.5952371461977648 0.62732823319059772} atlasBounds {152.5 167.5 171.5 191.5}} {advance 0.599609375 planeBounds {0.080240410896501496 -0.040397799744897905 0.54671271410349853 0.61266342474489799} atlasBounds {85.5 44.5 100.5 65.5}} {advance 0.599609375 planeBounds {0.035714522974368321 -0.052284767143464472 0.56438313327563161 0.63187461089346453} atlasBounds {166.5 89.5 183.5 111.5}} {advance 0.599609375 planeBounds {0.019921305575801802 -0.039177096619897905 0.57968806942419826 0.61388412786989799} atlasBounds {150.5 44.5 168.5 65.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.055214454643464472 0.54858991587706507 0.62894492339346453} atlasBounds {128.5 89.5 144.5 111.5}} {advance 0.599609375 planeBounds {0.0033956663022352371 -0.055214454643464472 0.5942605836977648 0.62894492339346453} atlasBounds {108.5 89.5 127.5 111.5}} {advance 0.599609375 planeBounds {-0.013129972971331333 -0.055214454643464472 0.60883309797133145 0.62894492339346453} atlasBounds {87.5 89.5 107.5 111.5}} {advance 0.599609375 planeBounds {0.038400069849368376 -0.052284767143464472 0.56706868015063172 0.63187461089346453} atlasBounds {69.5 89.5 86.5 111.5}} {advance 0.599609375 planeBounds {0.019921305575801802 -0.051308204643464472 0.57968806942419826 0.63285117339346453} atlasBounds {50.5 89.5 68.5 111.5}} {advance 0.599609375 planeBounds {0.034982101099368321 -0.036735690369897905 0.56365071140063161 0.61632553411989799} atlasBounds {174.5 67.5 191.5 88.5}} {advance 0.599609375 planeBounds {0.12192890549076774 -0.19726111705843047 0.46400859450923226 0.70458533580843052} atlasBounds {111.5 162.5 122.5 191.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.21281019383199704 0.54858991587706507 0.72013441258199706} atlasBounds {47.5 161.5 63.5 191.5}} {advance 0.599609375 planeBounds {0.13560078049076774 -0.19726111705843047 0.47768046950923226 0.70458533580843052} atlasBounds {123.5 162.5 134.5 191.5}} {advance 0.599609375 planeBounds {0.081873472045068063 0.20003753454506806 0.51724762170493199 0.63541168420493199} atlasBounds {105.5 10.5 119.5 24.5}} {advance 0.599609375 planeBounds {-0.011176847971331333 -0.23448366511783283 0.61078622297133145 -0.078992897382167152} atlasBounds {0.5 0.5 20.5 5.5}} {advance 0.599609375 planeBounds {0.1189232947643343 0.47448433893646752 0.42990483023566567 0.72326956731353265} atlasBounds {161.5 16.5 171.5 24.5}} {advance 0.599609375 planeBounds {0.037591724747934922 -0.054297444424198246 0.53516218150206507 0.50546931942419826} atlasBounds {56.5 25.5 72.5 43.5}} {advance 0.599609375 planeBounds {0.048409835474368376 -0.055795030065597606 0.57707844577563172 0.69056065506559772} atlasBounds {0.5 136.5 17.5 160.5}} {advance 0.599609375 planeBounds {0.033517257349368376 -0.054297444424198246 0.56218586765063172 0.50546931942419826} atlasBounds {19.5 25.5 36.5 43.5}} {advance 0.599609375 planeBounds {0.022530929224368376 -0.055795030065597606 0.55119953952563172 0.69056065506559772} atlasBounds {54.5 136.5 71.5 160.5}} {advance 0.599609375 planeBounds {0.037721901446590565 -0.054297444424198246 0.56639051174785393 0.50546931942419826} atlasBounds {92.5 25.5 109.5 43.5}} {advance 0.599609375 planeBounds {0.053536788599368376 -0.038536968917031039 0.58220539890063172 0.67672056266703107} atlasBounds {18.5 112.5 35.5 135.5}} {advance 0.599609375 planeBounds {0.022530929224368376 -0.24231846756559769 0.55119953952563172 0.50403721756559761} atlasBounds {72.5 136.5 89.5 160.5}} {advance 0.599609375 planeBounds {0.055413990372934915 -0.037316265792031039 0.55298444712706507 0.67794126579203107} atlasBounds {169.5 137.5 185.5 160.5}} {advance 0.599609375 planeBounds {0.049142257349368376 -0.040414170690597613 0.57781086765063172 0.70594151444059772} atlasBounds {90.5 136.5 107.5 160.5}} {advance 0.599609375 planeBounds {0.049158628295068028 -0.23380628758199704 0.48453277795493194 0.69913831883199706} atlasBounds {64.5 161.5 78.5 191.5}} {advance 0.599609375 planeBounds {0.071527271622934915 -0.054330186315597606 0.56909772837706507 0.69202549881559772} atlasBounds {108.5 136.5 124.5 160.5}} {advance 0.599609375 planeBounds {0.044259444849368376 -0.037316265792031039 0.57292805515063172 0.67794126579203107} atlasBounds {151.5 137.5 168.5 160.5}} {advance 0.599609375 planeBounds {0.020409586825801802 -0.051367756924198246 0.58017635067419826 0.50839900692419826} atlasBounds {0.5 25.5 18.5 43.5}} {advance 0.599609375 planeBounds {0.055413990372934915 -0.051367756924198246 0.55298444712706507 0.50839900692419826} atlasBounds {143.5 25.5 159.5 43.5}} {advance 0.599609375 planeBounds {0.019921305575801809 -0.054297444424198246 0.57968806942419826 0.50546931942419826} atlasBounds {37.5 25.5 55.5 43.5}} {advance 0.599609375 planeBounds {0.048409835474368376 -0.23938878006559769 0.57707844577563172 0.50696690506559761} atlasBounds {36.5 136.5 53.5 160.5}} {advance 0.599609375 planeBounds {0.022530929224368376 -0.23938878006559769 0.55119953952563172 0.50696690506559761} atlasBounds {18.5 136.5 35.5 160.5}} {advance 0.599609375 planeBounds {0.1066075983965015 -0.051367756924198246 0.57307990160349853 0.50839900692419826} atlasBounds {127.5 25.5 142.5 43.5}} {advance 0.599609375 planeBounds {0.050531177872934915 -0.054297444424198246 0.54810163462706507 0.50546931942419826} atlasBounds {0.5 6.5 16.5 24.5}} {advance 0.599609375 planeBounds {0.016259196200801802 -0.052284767143464472 0.57602596004919826 0.63187461089346453} atlasBounds {72.5 113.5 90.5 135.5}} {advance 0.599609375 planeBounds {0.046624927872934922 -0.057227131924198246 0.54419538462706507 0.50253963192419826} atlasBounds {110.5 25.5 126.5 43.5}} {advance 0.599609375 planeBounds {0.019921305575801802 -0.056738850674198246 0.57968806942419826 0.50302791317419826} atlasBounds {73.5 25.5 91.5 43.5}} {advance 0.599609375 planeBounds {-0.011176847971331333 -0.057227131924198246 0.61078622297133145 0.50253963192419826} atlasBounds {169.5 47.5 189.5 65.5}} {advance 0.599609375 planeBounds {0.038400069849368376 -0.038748367650631679 0.56706868015063172 0.48992024265063167} atlasBounds {70.5 7.5 87.5 24.5}} {advance 0.599609375 planeBounds {0.019677164950801802 -0.22676939079203109 0.57944392879919826 0.48848814079203107} atlasBounds {132.5 137.5 150.5 160.5}} {advance 0.599609375 planeBounds {0.051019459122934915 -0.038748367650631679 0.54858991587706507 0.48992024265063167} atlasBounds {17.5 7.5 33.5 24.5}} {advance 0.599609375 planeBounds {0.051675957771501489 -0.19726111705843047 0.51814826097849853 0.70458533580843052} atlasBounds {95.5 162.5 110.5 191.5}} {advance 0.599609375 planeBounds {0.22205930363216717 -0.21281019383199704 0.37755007136783286 0.72013441258199706} atlasBounds {41.5 161.5 46.5 191.5}} {advance 0.599609375 planeBounds {0.081461114021501496 -0.19726111705843047 0.54793341722849853 0.70458533580843052} atlasBounds {79.5 162.5 94.5 191.5}} {advance 0.599609375 planeBounds {0.035470382349368376 0.17533615008503403 0.56413899265063172 0.393023224914966} atlasBounds {172.5 17.5 189.5 24.5}} {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}}} csv {32,0.599609375,0,0,0,0,0,0,0,0
33,0.599609375,0.20651022685860057,-0.050255718917031039,0.3930991481413994,0.66500181266703107,125.5,137.5,131.5,160.5
34,0.599609375,0.08463732817714352,0.31333515549076779,0.52001147783700741,0.65541484450923226,129.5,13.5,143.5,24.5
35,0.599609375,-0.011176847971331333,-0.052284767143464472,0.61078622297133145,0.63187461089346453,51.5,113.5,71.5,135.5
36,0.599609375,0.050531177872934915,-0.1455792277848639,0.54810163462706507,0.72516907153486398,135.5,163.5,151.5,191.5
37,0.599609375,-0.011176847971331333,-0.052284767143464472,0.61078622297133145,0.63187461089346453,91.5,113.5,111.5,135.5
38,0.599609375,0.040597335474368376,-0.053185406417031039,0.56926594577563172,0.66207212516703107,0.5,112.5,17.5,135.5
39,0.599609375,0.20658853611567607,0.31333515549076779,0.39317745739847487,0.65541484450923226,184.5,92.5,190.5,103.5
40,0.599609375,0.11265156174076774,-0.21305433445699704,0.45473125075923226,0.71989027195699706,0.5,161.5,11.5,191.5
41,0.599609375,0.14487812424076774,-0.21305433445699704,0.48695781325923226,0.71989027195699706,12.5,161.5,23.5,191.5
42,0.599609375,0.019921305575801802,0.030663493075801809,0.57968806942419826,0.59043025692419826,160.5,25.5,178.5,43.5
43,0.599609375,0.051019459122934915,0.035394459122934922,0.54858991587706507,0.53296491587706507,88.5,8.5,104.5,24.5
44,0.599609375,0.14928902643646744,-0.18658892128279883,0.39807425481353254,0.18658892128279883,120.5,12.5,128.5,24.5
45,0.599609375,0.051019459122934915,0.20643430363216717,0.54858991587706507,0.36192507136783286,21.5,0.5,37.5,5.5
46,0.599609375,0.19096115008503403,-0.038042756164965982,0.408648224914966,0.17964431866496597,184.5,104.5,191.5,111.5
47,0.599609375,0.051019459122934915,-0.21281019383199704,0.54858991587706507,0.72013441258199706,24.5,161.5,40.5,191.5
48,0.599609375,0.051019459122934915,-0.052284767143464472,0.54858991587706507,0.63187461089346453,112.5,113.5,128.5,135.5
49,0.599609375,0.073648614021501496,-0.046181251518464472,0.54012091722849853,0.63797812651846453,129.5,113.5,144.5,135.5
50,0.599609375,0.063150567146501496,-0.031364596619897905,0.52962287035349853,0.62169662786989799,69.5,44.5,84.5,65.5
51,0.599609375,0.054605645271501489,-0.052284767143464472,0.52107794847849853,0.63187461089346453,145.5,113.5,160.5,135.5
52,0.599609375,0.030587569849368376,-0.049355079643464472,0.55925618015063172,0.63480429839346453,161.5,113.5,178.5,135.5
53,0.599609375,0.058756035896501489,-0.042106784119897905,0.52522833910349853,0.61095444036989799,101.5,44.5,116.5,65.5
54,0.599609375,0.053216724747934915,-0.052272560112214539,0.55078718150206507,0.63188681792471446,0.5,89.5,16.5,111.5
55,0.599609375,0.051019459122934915,-0.042106784119897905,0.54858991587706507,0.61095444036989799,117.5,44.5,133.5,65.5
56,0.599609375,0.066568535896501496,-0.052284767143464472,0.53304083910349853,0.63187461089346453,17.5,89.5,32.5,111.5
57,0.599609375,0.048822193497934915,-0.052296974174714489,0.54639265025206507,0.63186240386221448,33.5,89.5,49.5,111.5
58,0.599609375,0.19096115008503403,-0.038748367650631679,0.408648224914966,0.48992024265063167,179.5,26.5,186.5,43.5
59,0.599609375,0.15905465143646744,-0.18582968901846453,0.40783987981353254,0.49832968901846447,179.5,113.5,187.5,135.5
60,0.599609375,0.023263351099368376,0.020333663599368376,0.55193196140063172,0.54900227390063172,34.5,7.5,51.5,24.5
61,0.599609375,0.051019459122934915,0.11313984299076774,0.54858991587706507,0.45521953200923226,144.5,13.5,160.5,24.5
62,0.599609375,0.047677413599368376,0.020333663599368376,0.57634602390063172,0.54900227390063172,52.5,7.5,69.5,24.5
63,0.599609375,0.082117612670068063,-0.050255718917031039,0.51749176232993199,0.66500181266703107,36.5,112.5,50.5,135.5
64,0.599609375,-0.013129972971331333,-0.11624961089346447,0.60883309797133145,0.56790976714346453,145.5,89.5,165.5,111.5
65,0.599609375,0.0033956663022352371,-0.049355079643464472,0.5942605836977648,0.63480429839346453,172.5,169.5,191.5,191.5
66,0.599609375,0.063470630997934915,-0.036735690369897905,0.56104108775206507,0.61632553411989799,52.5,44.5,68.5,65.5
67,0.599609375,0.034493819849368376,-0.052284767143464472,0.56316243015063172,0.63187461089346453,0.5,66.5,17.5,88.5
68,0.599609375,0.046944991724368376,-0.036735690369897905,0.57561360202563172,0.61632553411989799,16.5,44.5,33.5,65.5
69,0.599609375,0.075601739021501496,-0.036735690369897905,0.54207404222849853,0.61632553411989799,134.5,44.5,149.5,65.5
70,0.599609375,0.080484551521501496,-0.039177096619897905,0.54695685472849853,0.61388412786989799,0.5,44.5,15.5,65.5
71,0.599609375,0.011376383700801804,-0.052284767143464472,0.57114314754919826,0.63187461089346453,55.5,66.5,73.5,88.5
72,0.599609375,0.051019459122934915,-0.036735690369897905,0.54858991587706507,0.61632553411989799,141.5,67.5,157.5,88.5
73,0.599609375,0.051019459122934915,-0.036735690369897905,0.54858991587706507,0.61632553411989799,124.5,67.5,140.5,88.5
74,0.599609375,0.044595879646501461,-0.042106784119897905,0.51106818285349853,0.61095444036989799,108.5,67.5,123.5,88.5
75,0.599609375,0.071038990372934915,-0.051796485893464472,0.56860944712706507,0.63236289214346453,74.5,66.5,90.5,88.5
76,0.599609375,0.080484551521501496,-0.034294284119897905,0.54695685472849853,0.61876694036989799,158.5,67.5,173.5,88.5
77,0.599609375,0.035469584504188571,-0.036735690369897905,0.56413819480545191,0.61632553411989799,34.5,44.5,51.5,65.5
78,0.599609375,0.051019459122934915,-0.055214454643464472,0.54858991587706507,0.62894492339346453,38.5,66.5,54.5,88.5
79,0.599609375,0.0043722288022352371,-0.052284767143464472,0.5952371461977648,0.63187461089346453,18.5,66.5,37.5,88.5
80,0.599609375,0.070306568497934915,-0.039177096619897905,0.56787702525206507,0.61388412786989799,91.5,67.5,107.5,88.5
81,0.599609375,0.0043722288022352371,-0.11902745194059761,0.5952371461977648,0.62732823319059772,152.5,167.5,171.5,191.5
82,0.599609375,0.080240410896501496,-0.040397799744897905,0.54671271410349853,0.61266342474489799,85.5,44.5,100.5,65.5
83,0.599609375,0.035714522974368321,-0.052284767143464472,0.56438313327563161,0.63187461089346453,166.5,89.5,183.5,111.5
84,0.599609375,0.019921305575801802,-0.039177096619897905,0.57968806942419826,0.61388412786989799,150.5,44.5,168.5,65.5
85,0.599609375,0.051019459122934915,-0.055214454643464472,0.54858991587706507,0.62894492339346453,128.5,89.5,144.5,111.5
86,0.599609375,0.0033956663022352371,-0.055214454643464472,0.5942605836977648,0.62894492339346453,108.5,89.5,127.5,111.5
87,0.599609375,-0.013129972971331333,-0.055214454643464472,0.60883309797133145,0.62894492339346453,87.5,89.5,107.5,111.5
88,0.599609375,0.038400069849368376,-0.052284767143464472,0.56706868015063172,0.63187461089346453,69.5,89.5,86.5,111.5
89,0.599609375,0.019921305575801802,-0.051308204643464472,0.57968806942419826,0.63285117339346453,50.5,89.5,68.5,111.5
90,0.599609375,0.034982101099368321,-0.036735690369897905,0.56365071140063161,0.61632553411989799,174.5,67.5,191.5,88.5
91,0.599609375,0.12192890549076774,-0.19726111705843047,0.46400859450923226,0.70458533580843052,111.5,162.5,122.5,191.5
92,0.599609375,0.051019459122934915,-0.21281019383199704,0.54858991587706507,0.72013441258199706,47.5,161.5,63.5,191.5
93,0.599609375,0.13560078049076774,-0.19726111705843047,0.47768046950923226,0.70458533580843052,123.5,162.5,134.5,191.5
94,0.599609375,0.081873472045068063,0.20003753454506806,0.51724762170493199,0.63541168420493199,105.5,10.5,119.5,24.5
95,0.599609375,-0.011176847971331333,-0.23448366511783283,0.61078622297133145,-0.078992897382167152,0.5,0.5,20.5,5.5
96,0.599609375,0.1189232947643343,0.47448433893646752,0.42990483023566567,0.72326956731353265,161.5,16.5,171.5,24.5
97,0.599609375,0.037591724747934922,-0.054297444424198246,0.53516218150206507,0.50546931942419826,56.5,25.5,72.5,43.5
98,0.599609375,0.048409835474368376,-0.055795030065597606,0.57707844577563172,0.69056065506559772,0.5,136.5,17.5,160.5
99,0.599609375,0.033517257349368376,-0.054297444424198246,0.56218586765063172,0.50546931942419826,19.5,25.5,36.5,43.5
100,0.599609375,0.022530929224368376,-0.055795030065597606,0.55119953952563172,0.69056065506559772,54.5,136.5,71.5,160.5
101,0.599609375,0.037721901446590565,-0.054297444424198246,0.56639051174785393,0.50546931942419826,92.5,25.5,109.5,43.5
102,0.599609375,0.053536788599368376,-0.038536968917031039,0.58220539890063172,0.67672056266703107,18.5,112.5,35.5,135.5
103,0.599609375,0.022530929224368376,-0.24231846756559769,0.55119953952563172,0.50403721756559761,72.5,136.5,89.5,160.5
104,0.599609375,0.055413990372934915,-0.037316265792031039,0.55298444712706507,0.67794126579203107,169.5,137.5,185.5,160.5
105,0.599609375,0.049142257349368376,-0.040414170690597613,0.57781086765063172,0.70594151444059772,90.5,136.5,107.5,160.5
106,0.599609375,0.049158628295068028,-0.23380628758199704,0.48453277795493194,0.69913831883199706,64.5,161.5,78.5,191.5
107,0.599609375,0.071527271622934915,-0.054330186315597606,0.56909772837706507,0.69202549881559772,108.5,136.5,124.5,160.5
108,0.599609375,0.044259444849368376,-0.037316265792031039,0.57292805515063172,0.67794126579203107,151.5,137.5,168.5,160.5
109,0.599609375,0.020409586825801802,-0.051367756924198246,0.58017635067419826,0.50839900692419826,0.5,25.5,18.5,43.5
110,0.599609375,0.055413990372934915,-0.051367756924198246,0.55298444712706507,0.50839900692419826,143.5,25.5,159.5,43.5
111,0.599609375,0.019921305575801809,-0.054297444424198246,0.57968806942419826,0.50546931942419826,37.5,25.5,55.5,43.5
112,0.599609375,0.048409835474368376,-0.23938878006559769,0.57707844577563172,0.50696690506559761,36.5,136.5,53.5,160.5
113,0.599609375,0.022530929224368376,-0.23938878006559769,0.55119953952563172,0.50696690506559761,18.5,136.5,35.5,160.5
114,0.599609375,0.1066075983965015,-0.051367756924198246,0.57307990160349853,0.50839900692419826,127.5,25.5,142.5,43.5
115,0.599609375,0.050531177872934915,-0.054297444424198246,0.54810163462706507,0.50546931942419826,0.5,6.5,16.5,24.5
116,0.599609375,0.016259196200801802,-0.052284767143464472,0.57602596004919826,0.63187461089346453,72.5,113.5,90.5,135.5
117,0.599609375,0.046624927872934922,-0.057227131924198246,0.54419538462706507,0.50253963192419826,110.5,25.5,126.5,43.5
118,0.599609375,0.019921305575801802,-0.056738850674198246,0.57968806942419826,0.50302791317419826,73.5,25.5,91.5,43.5
119,0.599609375,-0.011176847971331333,-0.057227131924198246,0.61078622297133145,0.50253963192419826,169.5,47.5,189.5,65.5
120,0.599609375,0.038400069849368376,-0.038748367650631679,0.56706868015063172,0.48992024265063167,70.5,7.5,87.5,24.5
121,0.599609375,0.019677164950801802,-0.22676939079203109,0.57944392879919826,0.48848814079203107,132.5,137.5,150.5,160.5
122,0.599609375,0.051019459122934915,-0.038748367650631679,0.54858991587706507,0.48992024265063167,17.5,7.5,33.5,24.5
123,0.599609375,0.051675957771501489,-0.19726111705843047,0.51814826097849853,0.70458533580843052,95.5,162.5,110.5,191.5
124,0.599609375,0.22205930363216717,-0.21281019383199704,0.37755007136783286,0.72013441258199706,41.5,161.5,46.5,191.5
125,0.599609375,0.081461114021501496,-0.19726111705843047,0.54793341722849853,0.70458533580843052,79.5,162.5,94.5,191.5
126,0.599609375,0.035470382349368376,0.17533615008503403,0.56413899265063172,0.393023224914966,172.5,17.5,189.5,24.5
} fields {} line {} values {} i 128 atlasBottom 17.5 planeBottom 0.17533615008503403 atlasTop 24.5 name CourierPrimeCode advance 0.599609375 atlasRight 189.5 planeTop 0.393023224914966 planeRight 0.56413899265063172 atlasLeft 172.5 planeLeft 0.035470382349368376 defaultGlyphInfo {advance 0.599609375 planeBounds {0.082117612670068063 -0.050255718917031039 0.51749176232993199 0.66500181266703107} atlasBounds {36.5 112.5 50.5 135.5}} im {width {192} height {192} components {3} bytesPerRow {576} uniq {0} data {(uint8_t*) 0x79d17c42a090}} csvFd ::aio.handle211}}
when the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} dat (
[ m18009:0 (s23879:0) ]
)when the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c466c40}} as texture /gim/ \n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {^loadImage {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} ^loadFont {name \n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ {builtin-programs/draw/text.folk 174}} glyphIdx {} glyphInfos {{advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0 0 0 0} atlasBounds {0 0 0 0}} {advance 0.5859375 planeBounds {0.18506894267822735 -0.0071826265956166247 0.40086855732177262 0.76353028284561653} atlasBounds {131.5 119.5 138.5 144.5}} {advance 0.5859375 planeBounds {0.092583393545279377 0.33672401854527934 0.49335410645472061 0.73749473145472055} atlasBounds {170.5 26.5 183.5 39.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {156.5 119.5 174.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.2011201303588632 0.55501113921001921 0.87787794285886322} atlasBounds {0.5 172.5 17.5 207.5}} {advance 0.5859375 planeBounds {-0.01531641377649331 -0.054091025409441287 0.60125391377649318 0.74745040040944122} atlasBounds {0.5 145.5 20.5 171.5}} {advance 0.5859375 planeBounds {-0.01531641377649331 -0.044569541034441287 0.60125391377649318 0.75697188478444122} atlasBounds {40.5 145.5 60.5 171.5}} {advance 0.5859375 planeBounds {0.20048320086705201 0.33672401854527934 0.38545429913294799 0.73749473145472055} atlasBounds {163.5 26.5 169.5 39.5}} {advance 0.5859375 planeBounds {0.10799765173410404 -0.17782657454238926 0.47793984826589592 0.80868594954238915} atlasBounds {25.5 175.5 37.5 207.5}} {advance 0.5859375 planeBounds {0.10799765173410404 -0.17489688704238926 0.47793984826589592 0.81161563704238915} atlasBounds {68.5 175.5 80.5 207.5}} {advance 0.5859375 planeBounds {0.015512102601156015 0.088055267039980678 0.5704253973988439 0.61214004546001921} atlasBounds {117.5 22.5 135.5 39.5}} {advance 0.5859375 planeBounds {0.015512102601156015 0.053320500662331349 0.5704253973988439 0.63906231183766848} atlasBounds {112.5 0.5 130.5 19.5}} {advance 0.5859375 planeBounds {0.18506894267822735 -0.23261191895472061 0.40086855732177262 0.16815879395472061} atlasBounds {155.5 26.5 162.5 39.5}} {advance 0.5859375 planeBounds {0.015267961976156015 0.25468241961705201 0.5701812567738439 0.43965351788294799} atlasBounds {131.5 3.5 149.5 9.5}} {advance 0.5859375 planeBounds {0.20048320086705201 -0.028520705382947972 0.38545429913294799 0.15645039288294799} atlasBounds {191.5 145.5 197.5 151.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.1697365351035646 0.55501113921001921 0.78594747260356446} atlasBounds {99.5 176.5 116.5 207.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.054091025409441287 0.5704253973988439 0.74745040040944122} atlasBounds {80.5 145.5 98.5 171.5}} {advance 0.5859375 planeBounds {0.12341190992292871 -0.038676767220616623 0.46252559007707128 0.73203614222061653} atlasBounds {175.5 119.5 186.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980678 -0.033793954720616623 0.55501113921001921 0.73691895472061653} atlasBounds {112.5 92.5 129.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.046733407845616623 0.5704253973988439 0.72397950159561653} atlasBounds {149.5 92.5 167.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038432626595616623 0.5704253973988439 0.73228028284561653} atlasBounds {187.5 92.5 205.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.043559579720616623 0.5704253973988439 0.72715332972061653} atlasBounds {132.5 66.5 150.5 91.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.043559579720616623 0.55501113921001921 0.72715332972061653} atlasBounds {0.5 40.5 17.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.036967782845616623 0.5704253973988439 0.73374512659561653} atlasBounds {56.5 40.5 74.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.054091025409441287 0.5704253973988439 0.74745040040944122} atlasBounds {99.5 145.5 117.5 171.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.034770517220616623 0.55501113921001921 0.73594239222061653} atlasBounds {92.5 40.5 109.5 65.5}} {advance 0.5859375 planeBounds {0.20048320086705201 -0.032372858712668651 0.38545429913294799 0.55336895246266848} atlasBounds {18.5 20.5 24.5 39.5}} {advance 0.5859375 planeBounds {0.16965468448940269 -0.22178223597061664 0.41628281551059726 0.54893067347061653} atlasBounds {199.5 182.5 207.5 207.5}} {advance 0.5859375 planeBounds {-0.030730671965317972 0.026398234284682021 0.61666817196531787 0.67379707821531787} atlasBounds {148.5 44.5 169.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 0.14775917479527936 0.5704253973988439 0.54852988770472055} atlasBounds {136.5 26.5 154.5 39.5}} {advance 0.5859375 planeBounds {-0.030730671965317972 0.017609171784682028 0.61666817196531787 0.66500801571531787} atlasBounds {170.5 44.5 191.5 65.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.018102157092967294 0.5704253973988439 0.69095371959296714} atlasBounds {129.5 42.5 147.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {37.5 40.5 55.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {18.5 40.5 36.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.059950400409441287 0.5704253973988439 0.74159102540944122} atlasBounds {153.5 145.5 171.5 171.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {187.5 66.5 205.5 91.5}} {advance 0.5859375 planeBounds {0.031414642039980727 -0.039409189095616623 0.55549942046001921 0.73130372034561653} atlasBounds {169.5 66.5 186.5 91.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.038676767220616623 0.55501113921001921 0.73203614222061653} atlasBounds {151.5 66.5 168.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.050428916034441287 0.5704253973988439 0.75111250978444122} atlasBounds {74.5 118.5 92.5 144.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {113.5 66.5 131.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038188485970616623 0.5704253973988439 0.73252442347061653} atlasBounds {94.5 66.5 112.5 91.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.039165048470616623 0.55501113921001921 0.73154786097061653} atlasBounds {76.5 66.5 93.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {57.5 66.5 75.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039165048470616623 0.5704253973988439 0.73154786097061653} atlasBounds {38.5 66.5 56.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039653329720616623 0.5704253973988439 0.73105957972061653} atlasBounds {19.5 66.5 37.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {0.5 66.5 18.5 91.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.046766806659441287 0.5704253973988439 0.75477461915944122} atlasBounds {93.5 118.5 111.5 144.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038188485970616623 0.5704253973988439 0.73252442347061653} atlasBounds {168.5 92.5 186.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.16994727691473993 0.5704253973988439 0.75490821441473988} atlasBounds {161.5 177.5 179.5 207.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.038676767220616623 0.5704253973988439 0.73203614222061653} atlasBounds {130.5 92.5 148.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.056776572284441287 0.5704253973988439 0.74476485353444122} atlasBounds {112.5 118.5 130.5 144.5}} {advance 0.5859375 planeBounds {-0.01531641377649331 -0.038920907845616623 0.60125391377649318 0.73179200159561653} atlasBounds {187.5 119.5 207.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.038676767220616623 0.55501113921001921 0.73203614222061653} atlasBounds {75.5 92.5 92.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039409189095616623 0.5704253973988439 0.73130372034561653} atlasBounds {56.5 92.5 74.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039653329720616623 0.5704253973988439 0.73105957972061653} atlasBounds {37.5 92.5 55.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039653329720616623 0.5704253973988439 0.73105957972061653} atlasBounds {18.5 92.5 36.5 117.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039409189095616623 0.5704253973988439 0.73130372034561653} atlasBounds {93.5 92.5 111.5 117.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.038676767220616623 0.55501113921001921 0.73203614222061653} atlasBounds {0.5 92.5 17.5 117.5}} {advance 0.5859375 planeBounds {0.10799765173410404 -0.1311623163535646 0.47793984826589592 0.82452169135356446} atlasBounds {117.5 176.5 129.5 207.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.1692482538535646 0.55501113921001921 0.78643575385356446} atlasBounds {130.5 176.5 147.5 207.5}} {advance 0.5859375 planeBounds {0.10799765173410404 -0.1311623163535646 0.47793984826589592 0.82452169135356446} atlasBounds {148.5 176.5 160.5 207.5}} {advance 0.5859375 planeBounds {0.077169135356454713 0.36165976110910397 0.50876836464354525 0.73160195764089586} atlasBounds {192.5 53.5 206.5 65.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.12004004094412332 0.5704253973988439 0.034102540944123301} atlasBounds {150.5 4.5 168.5 9.5}} {advance 0.5859375 planeBounds {0.15424042630057802 0.50092011380057799 0.43169707369942195 0.7783767611994219} atlasBounds {184.5 30.5 193.5 39.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.045068171212668651 0.5704253973988439 0.54067363996266848} atlasBounds {19.5 0.5 37.5 19.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.037489462909441287 0.5704253973988439 0.76405196290944122} atlasBounds {55.5 118.5 73.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.042870905587668651 0.55501113921001921 0.54287090558766848} atlasBounds {94.5 0.5 111.5 19.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.035536337909441287 0.5704253973988439 0.76600508790944122} atlasBounds {18.5 118.5 36.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.042382624337668651 0.55501113921001921 0.54335918683766848} atlasBounds {80.5 20.5 97.5 39.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.034315634784441287 0.55501113921001921 0.76722579103444122} atlasBounds {0.5 118.5 17.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.25965743165944133 0.55501113921001921 0.54188399415944111} atlasBounds {37.5 118.5 54.5 144.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.034071494159441287 0.5704253973988439 0.76746993165944122} atlasBounds {172.5 145.5 190.5 171.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.039653329720616623 0.5704253973988439 0.73105957972061653} atlasBounds {110.5 40.5 128.5 65.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.26034610579238932 0.55501113921001921 0.72616641829238915} atlasBounds {81.5 175.5 98.5 207.5}} {advance 0.5859375 planeBounds {0.061754877167630028 -0.034559775409441287 0.52418262283236994 0.76698165040944122} atlasBounds {118.5 145.5 133.5 171.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.052171299223265952 0.5704253973988439 0.7801986429732658} atlasBounds {180.5 180.5 198.5 207.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.041161921212668651 0.5704253973988439 0.54457988996266848} atlasBounds {98.5 20.5 116.5 39.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.040917780587668651 0.55501113921001921 0.54482403058766848} atlasBounds {38.5 0.5 55.5 19.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.042870905587668651 0.55501113921001921 0.54287090558766848} atlasBounds {25.5 20.5 42.5 39.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.26429610353444133 0.5704253973988439 0.53724532228444111} atlasBounds {21.5 145.5 39.5 171.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.26478438478444133 0.5704253973988439 0.53675704103444111} atlasBounds {134.5 145.5 152.5 171.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.041894343087668651 0.5704253973988439 0.54384746808766848} atlasBounds {61.5 20.5 79.5 39.5}} {advance 0.5859375 planeBounds {0.030926360789980671 -0.041161921212668651 0.55501113921001921 0.54457988996266848} atlasBounds {43.5 20.5 60.5 39.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.052104501595616623 0.53959688102119452 0.71860840784561653} atlasBounds {139.5 119.5 155.5 144.5}} {advance 0.5859375 planeBounds {0.030926360789980727 -0.043603327462668651 0.55501113921001921 0.54213848371266848} atlasBounds {0.5 20.5 17.5 39.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.040673639962668651 0.5704253973988439 0.54506817121266848} atlasBounds {0.5 0.5 18.5 19.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.041650202462668651 0.5704253973988439 0.54409160871266848} atlasBounds {75.5 0.5 93.5 19.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.040185358712668651 0.5704253973988439 0.54555645246266848} atlasBounds {56.5 0.5 74.5 19.5}} {advance 0.5859375 planeBounds {0.015512102601156015 -0.26722579103444133 0.5704253973988439 0.53431563478444111} atlasBounds {61.5 145.5 79.5 171.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.040917780587668651 0.53959688102119452 0.54482403058766848} atlasBounds {191.5 152.5 207.5 171.5}} {advance 0.5859375 planeBounds {0.077169135356454685 -0.14852969954238926 0.50876836464354525 0.83798282454238915} atlasBounds {53.5 175.5 67.5 207.5}} {advance 0.5859375 planeBounds {0.20048320086705201 -0.1781709116088632 0.38545429913294799 0.90082716160886322} atlasBounds {18.5 172.5 24.5 207.5}} {advance 0.5859375 planeBounds {0.077169135356454685 -0.14852969954238926 0.50876836464354525 0.83798282454238915} atlasBounds {38.5 175.5 52.5 207.5}} {advance 0.5859375 planeBounds {0.015512102601156015 0.20770722317557802 0.5704253973988439 0.48516387057442195} atlasBounds {131.5 10.5 149.5 19.5}} {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}}} csv {32,0.5859375,0,0,0,0,0,0,0,0
33,0.5859375,0.18506894267822735,-0.0071826265956166247,0.40086855732177262,0.76353028284561653,131.5,119.5,138.5,144.5
34,0.5859375,0.092583393545279377,0.33672401854527934,0.49335410645472061,0.73749473145472055,170.5,26.5,183.5,39.5
35,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,156.5,119.5,174.5,144.5
36,0.5859375,0.030926360789980671,-0.2011201303588632,0.55501113921001921,0.87787794285886322,0.5,172.5,17.5,207.5
37,0.5859375,-0.01531641377649331,-0.054091025409441287,0.60125391377649318,0.74745040040944122,0.5,145.5,20.5,171.5
38,0.5859375,-0.01531641377649331,-0.044569541034441287,0.60125391377649318,0.75697188478444122,40.5,145.5,60.5,171.5
39,0.5859375,0.20048320086705201,0.33672401854527934,0.38545429913294799,0.73749473145472055,163.5,26.5,169.5,39.5
40,0.5859375,0.10799765173410404,-0.17782657454238926,0.47793984826589592,0.80868594954238915,25.5,175.5,37.5,207.5
41,0.5859375,0.10799765173410404,-0.17489688704238926,0.47793984826589592,0.81161563704238915,68.5,175.5,80.5,207.5
42,0.5859375,0.015512102601156015,0.088055267039980678,0.5704253973988439,0.61214004546001921,117.5,22.5,135.5,39.5
43,0.5859375,0.015512102601156015,0.053320500662331349,0.5704253973988439,0.63906231183766848,112.5,0.5,130.5,19.5
44,0.5859375,0.18506894267822735,-0.23261191895472061,0.40086855732177262,0.16815879395472061,155.5,26.5,162.5,39.5
45,0.5859375,0.015267961976156015,0.25468241961705201,0.5701812567738439,0.43965351788294799,131.5,3.5,149.5,9.5
46,0.5859375,0.20048320086705201,-0.028520705382947972,0.38545429913294799,0.15645039288294799,191.5,145.5,197.5,151.5
47,0.5859375,0.030926360789980671,-0.1697365351035646,0.55501113921001921,0.78594747260356446,99.5,176.5,116.5,207.5
48,0.5859375,0.015512102601156015,-0.054091025409441287,0.5704253973988439,0.74745040040944122,80.5,145.5,98.5,171.5
49,0.5859375,0.12341190992292871,-0.038676767220616623,0.46252559007707128,0.73203614222061653,175.5,119.5,186.5,144.5
50,0.5859375,0.030926360789980678,-0.033793954720616623,0.55501113921001921,0.73691895472061653,112.5,92.5,129.5,117.5
51,0.5859375,0.015512102601156015,-0.046733407845616623,0.5704253973988439,0.72397950159561653,149.5,92.5,167.5,117.5
52,0.5859375,0.015512102601156015,-0.038432626595616623,0.5704253973988439,0.73228028284561653,187.5,92.5,205.5,117.5
53,0.5859375,0.015512102601156015,-0.043559579720616623,0.5704253973988439,0.72715332972061653,132.5,66.5,150.5,91.5
54,0.5859375,0.030926360789980671,-0.043559579720616623,0.55501113921001921,0.72715332972061653,0.5,40.5,17.5,65.5
55,0.5859375,0.015512102601156015,-0.036967782845616623,0.5704253973988439,0.73374512659561653,56.5,40.5,74.5,65.5
56,0.5859375,0.015512102601156015,-0.054091025409441287,0.5704253973988439,0.74745040040944122,99.5,145.5,117.5,171.5
57,0.5859375,0.030926360789980671,-0.034770517220616623,0.55501113921001921,0.73594239222061653,92.5,40.5,109.5,65.5
58,0.5859375,0.20048320086705201,-0.032372858712668651,0.38545429913294799,0.55336895246266848,18.5,20.5,24.5,39.5
59,0.5859375,0.16965468448940269,-0.22178223597061664,0.41628281551059726,0.54893067347061653,199.5,182.5,207.5,207.5
60,0.5859375,-0.030730671965317972,0.026398234284682021,0.61666817196531787,0.67379707821531787,148.5,44.5,169.5,65.5
61,0.5859375,0.015512102601156015,0.14775917479527936,0.5704253973988439,0.54852988770472055,136.5,26.5,154.5,39.5
62,0.5859375,-0.030730671965317972,0.017609171784682028,0.61666817196531787,0.66500801571531787,170.5,44.5,191.5,65.5
63,0.5859375,0.046340618978805363,-0.030864267220616623,0.53959688102119452,0.73984864222061653,75.5,40.5,91.5,65.5
64,0.5859375,0.015512102601156015,-0.018102157092967294,0.5704253973988439,0.69095371959296714,129.5,42.5,147.5,65.5
65,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,37.5,40.5,55.5,65.5
66,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,18.5,40.5,36.5,65.5
67,0.5859375,0.015512102601156015,-0.059950400409441287,0.5704253973988439,0.74159102540944122,153.5,145.5,171.5,171.5
68,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,187.5,66.5,205.5,91.5
69,0.5859375,0.031414642039980727,-0.039409189095616623,0.55549942046001921,0.73130372034561653,169.5,66.5,186.5,91.5
70,0.5859375,0.030926360789980671,-0.038676767220616623,0.55501113921001921,0.73203614222061653,151.5,66.5,168.5,91.5
71,0.5859375,0.015512102601156015,-0.050428916034441287,0.5704253973988439,0.75111250978444122,74.5,118.5,92.5,144.5
72,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,113.5,66.5,131.5,91.5
73,0.5859375,0.015512102601156015,-0.038188485970616623,0.5704253973988439,0.73252442347061653,94.5,66.5,112.5,91.5
74,0.5859375,0.030926360789980671,-0.039165048470616623,0.55501113921001921,0.73154786097061653,76.5,66.5,93.5,91.5
75,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,57.5,66.5,75.5,91.5
76,0.5859375,0.015512102601156015,-0.039165048470616623,0.5704253973988439,0.73154786097061653,38.5,66.5,56.5,91.5
77,0.5859375,0.015512102601156015,-0.039653329720616623,0.5704253973988439,0.73105957972061653,19.5,66.5,37.5,91.5
78,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,0.5,66.5,18.5,91.5
79,0.5859375,0.015512102601156015,-0.046766806659441287,0.5704253973988439,0.75477461915944122,93.5,118.5,111.5,144.5
80,0.5859375,0.015512102601156015,-0.038188485970616623,0.5704253973988439,0.73252442347061653,168.5,92.5,186.5,117.5
81,0.5859375,0.015512102601156015,-0.16994727691473993,0.5704253973988439,0.75490821441473988,161.5,177.5,179.5,207.5
82,0.5859375,0.015512102601156015,-0.038676767220616623,0.5704253973988439,0.73203614222061653,130.5,92.5,148.5,117.5
83,0.5859375,0.015512102601156015,-0.056776572284441287,0.5704253973988439,0.74476485353444122,112.5,118.5,130.5,144.5
84,0.5859375,-0.01531641377649331,-0.038920907845616623,0.60125391377649318,0.73179200159561653,187.5,119.5,207.5,144.5
85,0.5859375,0.030926360789980671,-0.038676767220616623,0.55501113921001921,0.73203614222061653,75.5,92.5,92.5,117.5
86,0.5859375,0.015512102601156015,-0.039409189095616623,0.5704253973988439,0.73130372034561653,56.5,92.5,74.5,117.5
87,0.5859375,0.015512102601156015,-0.039653329720616623,0.5704253973988439,0.73105957972061653,37.5,92.5,55.5,117.5
88,0.5859375,0.015512102601156015,-0.039653329720616623,0.5704253973988439,0.73105957972061653,18.5,92.5,36.5,117.5
89,0.5859375,0.015512102601156015,-0.039409189095616623,0.5704253973988439,0.73130372034561653,93.5,92.5,111.5,117.5
90,0.5859375,0.030926360789980671,-0.038676767220616623,0.55501113921001921,0.73203614222061653,0.5,92.5,17.5,117.5
91,0.5859375,0.10799765173410404,-0.1311623163535646,0.47793984826589592,0.82452169135356446,117.5,176.5,129.5,207.5
92,0.5859375,0.030926360789980671,-0.1692482538535646,0.55501113921001921,0.78643575385356446,130.5,176.5,147.5,207.5
93,0.5859375,0.10799765173410404,-0.1311623163535646,0.47793984826589592,0.82452169135356446,148.5,176.5,160.5,207.5
94,0.5859375,0.077169135356454713,0.36165976110910397,0.50876836464354525,0.73160195764089586,192.5,53.5,206.5,65.5
95,0.5859375,0.015512102601156015,-0.12004004094412332,0.5704253973988439,0.034102540944123301,150.5,4.5,168.5,9.5
96,0.5859375,0.15424042630057802,0.50092011380057799,0.43169707369942195,0.7783767611994219,184.5,30.5,193.5,39.5
97,0.5859375,0.015512102601156015,-0.045068171212668651,0.5704253973988439,0.54067363996266848,19.5,0.5,37.5,19.5
98,0.5859375,0.015512102601156015,-0.037489462909441287,0.5704253973988439,0.76405196290944122,55.5,118.5,73.5,144.5
99,0.5859375,0.030926360789980671,-0.042870905587668651,0.55501113921001921,0.54287090558766848,94.5,0.5,111.5,19.5
100,0.5859375,0.015512102601156015,-0.035536337909441287,0.5704253973988439,0.76600508790944122,18.5,118.5,36.5,144.5
101,0.5859375,0.030926360789980671,-0.042382624337668651,0.55501113921001921,0.54335918683766848,80.5,20.5,97.5,39.5
102,0.5859375,0.030926360789980671,-0.034315634784441287,0.55501113921001921,0.76722579103444122,0.5,118.5,17.5,144.5
103,0.5859375,0.030926360789980671,-0.25965743165944133,0.55501113921001921,0.54188399415944111,37.5,118.5,54.5,144.5
104,0.5859375,0.015512102601156015,-0.034071494159441287,0.5704253973988439,0.76746993165944122,172.5,145.5,190.5,171.5
105,0.5859375,0.015512102601156015,-0.039653329720616623,0.5704253973988439,0.73105957972061653,110.5,40.5,128.5,65.5
106,0.5859375,0.030926360789980671,-0.26034610579238932,0.55501113921001921,0.72616641829238915,81.5,175.5,98.5,207.5
107,0.5859375,0.061754877167630028,-0.034559775409441287,0.52418262283236994,0.76698165040944122,118.5,145.5,133.5,171.5
108,0.5859375,0.015512102601156015,-0.052171299223265952,0.5704253973988439,0.7801986429732658,180.5,180.5,198.5,207.5
109,0.5859375,0.015512102601156015,-0.041161921212668651,0.5704253973988439,0.54457988996266848,98.5,20.5,116.5,39.5
110,0.5859375,0.030926360789980671,-0.040917780587668651,0.55501113921001921,0.54482403058766848,38.5,0.5,55.5,19.5
111,0.5859375,0.030926360789980671,-0.042870905587668651,0.55501113921001921,0.54287090558766848,25.5,20.5,42.5,39.5
112,0.5859375,0.015512102601156015,-0.26429610353444133,0.5704253973988439,0.53724532228444111,21.5,145.5,39.5,171.5
113,0.5859375,0.015512102601156015,-0.26478438478444133,0.5704253973988439,0.53675704103444111,134.5,145.5,152.5,171.5
114,0.5859375,0.015512102601156015,-0.041894343087668651,0.5704253973988439,0.54384746808766848,61.5,20.5,79.5,39.5
115,0.5859375,0.030926360789980671,-0.041161921212668651,0.55501113921001921,0.54457988996266848,43.5,20.5,60.5,39.5
116,0.5859375,0.046340618978805363,-0.052104501595616623,0.53959688102119452,0.71860840784561653,139.5,119.5,155.5,144.5
117,0.5859375,0.030926360789980727,-0.043603327462668651,0.55501113921001921,0.54213848371266848,0.5,20.5,17.5,39.5
118,0.5859375,0.015512102601156015,-0.040673639962668651,0.5704253973988439,0.54506817121266848,0.5,0.5,18.5,19.5
119,0.5859375,0.015512102601156015,-0.041650202462668651,0.5704253973988439,0.54409160871266848,75.5,0.5,93.5,19.5
120,0.5859375,0.015512102601156015,-0.040185358712668651,0.5704253973988439,0.54555645246266848,56.5,0.5,74.5,19.5
121,0.5859375,0.015512102601156015,-0.26722579103444133,0.5704253973988439,0.53431563478444111,61.5,145.5,79.5,171.5
122,0.5859375,0.046340618978805363,-0.040917780587668651,0.53959688102119452,0.54482403058766848,191.5,152.5,207.5,171.5
123,0.5859375,0.077169135356454685,-0.14852969954238926,0.50876836464354525,0.83798282454238915,53.5,175.5,67.5,207.5
124,0.5859375,0.20048320086705201,-0.1781709116088632,0.38545429913294799,0.90082716160886322,18.5,172.5,24.5,207.5
125,0.5859375,0.077169135356454685,-0.14852969954238926,0.50876836464354525,0.83798282454238915,38.5,175.5,52.5,207.5
126,0.5859375,0.015512102601156015,0.20770722317557802,0.5704253973988439,0.48516387057442195,131.5,10.5,149.5,19.5
} fields {} line {} values {} i 128 atlasBottom 10.5 planeBottom 0.20770722317557802 atlasTop 19.5 name NeomatrixCode advance 0.5859375 atlasRight 149.5 planeTop 0.48516387057442195 planeRight 0.5704253973988439 atlasLeft 131.5 planeLeft 0.015512102601156015 defaultGlyphInfo {advance 0.5859375 planeBounds {0.046340618978805363 -0.030864267220616623 0.53959688102119452 0.73984864222061653} atlasBounds {75.5 40.5 91.5 65.5}} im {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c466c40}} csvFd ::aio.handle212}}
when the GPU has loaded image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} dat ()when the GPU has loaded image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} as texture /gim/ \n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 11 options {image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} position {0 0} anchor topleft width 0.100666666667}} {} {id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {a {0 0} b {0.100666666667 0} radians 0 c {0.100666666667 0.100666666667} d {0 0.100666666667} x0 0 width 0.100666666667 y0 0 anchor topleft wiResolution {1024 1024} height 0.100666666667 im {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}}}}
when the GPU has loaded image {width {317} height {208} components {3} bytesPerRow {951} uniq {-78143 ()when the GPU has loaded image {width {317} height {208} components {3} bytesPerRow {951} uniq {-781439560} data {(uint8_t*) 0x79ccfbb83260}} as texture /gim/ \n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 63 options {image {width {317} height {208} components {3} bytesPerRow {951} uniq {-781439560} data {(uint8_t*) 0x79ccfbb83260}} position {0 0} anchor topleft width 0.100666666667}} {} {id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {a {0 0} b {0.100666666667 0} radians 0 c {0.100666666667 0.0660525762358} d {0 0.0660525762358} x0 0 width 0.100666666667 y0 0 anchor topleft wiResolution {1024 1024} height 0.0660525762358 im {width {317} height {208} components {3} bytesPerRow {951} uniq {-781439560} data {(uint8_t*) 0x79ccfbb83260}}}}
when the GPU has loaded image {width {95} height {62} components {3} bytesPerRow {285} uniq {-7814395 ()when the GPU has loaded image {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}} as texture /gim/ \n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 54-display options {image {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}} position {0 0} anchor topleft width 0.1055}} {} {id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {} {surfaceToClip {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}} {a {0 0} b {0.1055 0} radians 0 c {0.1055 0.0688526315789} d {0 0.0688526315789} x0 0 width 0.1055 y0 0 anchor topleft wiResolution {1024 1024} height 0.0688526315789 im {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}}}}
when the GPU has created canvas {monitor canvas} with /...canvOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ (
[ m23595:0 (s31257:0 s31258:0 s31259:0) ]
)when the GPU has created canvas {monitor canvas} with /...canvOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>} {disp monitor dispWidth 4096 dispHeight 2160} {dispCanvas {monitor canvas}}}
when the GPU has created canvas {11 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m25664:915 (s2798:1088) ]
)when the GPU has created canvas {11 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 11} {} {results {}} {writableTextureId {11 canvas} width 0.211 proj {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} k bottom top 0.03 left 0.151 bottom 0.079 v 79mm right 0.03 tagSize 0.03 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139} height 0.139}}
when the GPU has created canvas {82 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m6672:981 (s53224:1175) ]
)when the GPU has created canvas {82 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 82} {} {results {{geom {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}}}} {writableTextureId {82 canvas} marginLeft 0.01 lineHeight 0.003 marginBottom 0.007886 width 0.2159 proj {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} k marginLeft top 0.0246 advance 0.001758 left 0.1697 marginRight 0.009886 bottom 0.0921 v 10mm right 0.0232 tagSize 0.023 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397} height 0.1397 marginTop 0.01129}}
when the GPU has created canvas {54-display canvas} with /...canvOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ Clai (
[ m6677:989 (s53233:1173 s53234:1175) ]
)when the GPU has created canvas {54-display canvas} with /...canvOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>} {p 54-display options {settle 0ms width 1024 height 1024}} {pCanvas {54-display canvas}}}
when the GPU has created canvas {62 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m3061:1024 (s31845:1203) ]
)when the GPU has created canvas {62 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 62} {} {results {}} {writableTextureId {62 canvas} width 0.211 proj {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} k bottom top 0.03 left 0.151 bottom 0.079 v 79mm right 0.03 tagSize 0.03 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139} height 0.139}}
when the GPU has created canvas {63 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m44645:1033 (s51845:1230) ]
)when the GPU has created canvas {63 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 63} {} {results {}} {writableTextureId {63 canvas} width 0.211 proj {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} k bottom top 0.03 left 0.151 bottom 0.079 v 79mm right 0.03 tagSize 0.03 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139} height 0.139}}
when the GPU has created canvas {54 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m23352:1062 (s14681:1260) ]
)when the GPU has created canvas {54 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 54} {} {results {}} {writableTextureId {54 canvas} width 0.211 proj {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} k bottom top 0.03 left 0.151 bottom 0.079 v 79mm right 0.03 tagSize 0.03 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139} height 0.139}}
when the GPU has created canvas {83 canvas} with /...opts/ {
Claim $tag has canvas $writa (
[ m47725:1063 (s64489:1262) ]
)when the GPU has created canvas {83 canvas} with /...opts/ {
Claim $tag has canvas $writableTextureId with {*}$opts
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {} {tag 83} {} {results {{geom {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}}}} {writableTextureId {83 canvas} marginLeft 0.01 lineHeight 0.003 marginBottom 0.007886 width 0.2159 proj {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} k marginLeft top 0.0246 advance 0.001758 left 0.1697 marginRight 0.009886 bottom 0.0921 v 10mm right 0.0232 tagSize 0.023 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397} height 0.1397 marginTop 0.01129}}
when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[li (
[ m51789:1065 (s16246:1264) ]
)when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {position {2896.19187753 1020.39598124} scale 36.0 radians -1.56722363723 anchor bottom text {(edited Fri, 08 May 2026, 09:00 PM)}}} {radians -1.56722363723 x0 2896.19187753 y0 1020.39598124 anchor {0.5 1 0.5 1} layer 0 text {(edited Fri, 08 May 2026, 09:00 PM)} font PTSans-Regular scale 36.0 color {1.0 1.0 1.0 1.0}} {id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[li ()when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 options {x 0.1055 y 0.0995 scale 0.02 font PTSans-Regular text {FPS: 4
Frame count: 6}}} {radians 0 x0 0.1055 y0 0.0995 anchor {0.5 0.5 0.5 0.5} layer 0 text {FPS: 4
Frame count: 6} font PTSans-Regular scale 0.02 color {1.0 1.0 1.0 1.0}} {id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[li ()when the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {position {1650.08035762 776.516789771} scale 36.0 radians 0.0801624973828 anchor bottom text {(edited Mon, 15 Jun 2026, 06:30 PM)}}} {radians 0.0801624973828 x0 1650.08035762 y0 776.516789771 anchor {0.5 1 0.5 1} layer 0 text {(edited Mon, 15 Jun 2026, 06:30 PM)} font PTSans-Regular scale 36.0 color {1.0 1.0 1.0 1.0}} {id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when the GPU draw library is /drawLib/ {When the GPU VMA DLL is /vmaDll/ & the GPU texture library is (
[ m23440:0 (s30972:0) ]
)when the GPU draw library is /drawLib/ {When the GPU VMA DLL is /vmaDll/ & the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cflags -I./vendor
$cc endcflags $vmaDll
$cc include <png.h>
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
#include "vk_mem_alloc.h"
VmaAllocator vmaGetAllocator();
VkDevice device;
}
# HACK: to make gpuLib extend properly
$cc typedef {struct PushConstantsEncoder} PushConstantsEncoder
$cc typedef {struct Pipeline} Pipeline
$cc typedef {struct VmaAllocation_T*} VmaAllocation
$cc argtype VmaAllocation {
VmaAllocation $argname;
sscanf(Jim_String($obj), "(VmaAllocation) %p", &$argname);
}
$cc rtype VmaAllocation {
char buf[100];
snprintf(buf, 100, "(VmaAllocation) %p", $rvalue);
$robj = Jim_NewStringObj(interp, buf, -1);
}
$cc extend $gpuLib
$cc extend $imageLib
$cc extend $gpuTextureLib
$cc proc texturesLibInit {} void {
volkInitialize();
volkLoadInstanceOnly(*instance_ptr());
device = *device_ptr();
volkLoadDevice(device);
}
$cc proc copyTextureFromGpu {GpuTextureHandle han} Image {
GpuTextureBlock* block = getGpuTexture(han);
if (!block->alive) {
return (Image){0};
}
Image im = {
.width = block->width,
.height = block->height,
.components = 4, // HACK: hard-coded for now
.bytesPerRow = block->width * 4,
.data = malloc(block->width * block->height * 4)
};
VkBuffer stagingBuffer;
VmaAllocation stagingBufferAllocation;
size_t stagingBufferSize = block->width * block->height * 4;
createBuffer(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&stagingBuffer, &stagingBufferAllocation);
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = block->textureImage,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT
};
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
// Copy image to buffer
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {block->width, block->height, 1}
};
vkCmdCopyImageToBuffer(
commandBuffer,
block->textureImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
stagingBuffer,
1,
®ion
);
// Transition image layout back
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkFence fence = getFence();
endSingleTimeCommands(commandBuffer, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Copy staging buffer back to CPU
void* data;
vmaMapMemory(vmaGetAllocator(), stagingBufferAllocation, &data);
memcpy(im.data, data, stagingBufferSize);
vmaUnmapMemory(vmaGetAllocator(), stagingBufferAllocation);
// Cleanup staging buffer
vmaDestroyBuffer(vmaGetAllocator(), stagingBuffer, stagingBufferAllocation);
return im;
}
$cc code {
struct WriteState {
uint8_t* buffer;
size_t* size;
};
void pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
struct WriteState* state = (struct WriteState*)png_get_io_ptr(png_ptr);
memcpy(state->buffer + *state->size, data, length);
*state->size += length;
}
}
$cc proc imageToPngBuffer {Image im size_t* outSize} uint8_t* {
size_t bufferSize = im.width * im.height * im.components * 2; // max size estimate
uint8_t* buffer = malloc(bufferSize);
*outSize = 0;
png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_w) {
free(buffer);
return NULL;
}
png_infop info_w = png_create_info_struct(png_w);
if (!info_w) {
png_destroy_write_struct(&png_w, NULL);
free(buffer);
return NULL;
}
struct WriteState state = {
.buffer = buffer,
.size = outSize
};
png_set_write_fn(png_w, &state, pngWriteCallback, NULL);
if (im.components == 4) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else if (im.components == 3) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_destroy_write_struct(&png_w, &info_w);
free(buffer);
return NULL;
}
png_bytep* row_pointers = malloc(sizeof(png_bytep) * im.height);
for (int y = 0; y < im.height; y++) {
row_pointers[y] = im.data + y * im.bytesPerRow;
}
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
png_destroy_write_struct(&png_w, &info_w);
*outSize = bufferSize;
return buffer;
}
$cc proc copyAllTexturesFromGpu {} Jim_Obj* {
Jim_Obj* ret = Jim_NewListObj(interp, NULL, 0);
for (int i = 0; i < getMaxTextures(); i++) {
if (getGpuTexture(i)->alive) {
Image im = copyTextureFromGpu(i);
size_t pngSize;
uint8_t* pngData = imageToPngBuffer(im, &pngSize);
Jim_ListAppendElement(interp, ret, Jim_ObjPrintf("Image %d (%d x %d)", i, im.width, im.height));
Jim_ListAppendElement(interp, ret, Jim_NewStringObj(interp, (char*)pngData, pngSize));
free(pngData);
free(im.data);
}
}
return ret;
}
set texturesLib [$cc compile]
$texturesLib texturesLibInit
Wish the web server handles route {/textures} with handler {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
}
}} with environment {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {}}
when the GPU VMA DLL is /vmaDll/ {When the image library is /imageLib/ \n\nfn\ defineVulkanHandleType (
[ m13900:0 (s18540:0) ]
)when the GPU VMA DLL is /vmaDll/ {When the image library is /imageLib/ \n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n} with environment {{this builtin-programs/gpu/textures.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuLib <C:cfileog6zwp>} {}}
when the GPU VMA DLL is /vmaDll/ {When the GPU texture library is /gpuTextureLib/ {
set cc [C]
(
[ m23441:0 (s30973:0) ]
)when the GPU VMA DLL is /vmaDll/ {When the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cflags -I./vendor
$cc endcflags $vmaDll
$cc include <png.h>
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
#include "vk_mem_alloc.h"
VmaAllocator vmaGetAllocator();
VkDevice device;
}
# HACK: to make gpuLib extend properly
$cc typedef {struct PushConstantsEncoder} PushConstantsEncoder
$cc typedef {struct Pipeline} Pipeline
$cc typedef {struct VmaAllocation_T*} VmaAllocation
$cc argtype VmaAllocation {
VmaAllocation $argname;
sscanf(Jim_String($obj), "(VmaAllocation) %p", &$argname);
}
$cc rtype VmaAllocation {
char buf[100];
snprintf(buf, 100, "(VmaAllocation) %p", $rvalue);
$robj = Jim_NewStringObj(interp, buf, -1);
}
$cc extend $gpuLib
$cc extend $imageLib
$cc extend $gpuTextureLib
$cc proc texturesLibInit {} void {
volkInitialize();
volkLoadInstanceOnly(*instance_ptr());
device = *device_ptr();
volkLoadDevice(device);
}
$cc proc copyTextureFromGpu {GpuTextureHandle han} Image {
GpuTextureBlock* block = getGpuTexture(han);
if (!block->alive) {
return (Image){0};
}
Image im = {
.width = block->width,
.height = block->height,
.components = 4, // HACK: hard-coded for now
.bytesPerRow = block->width * 4,
.data = malloc(block->width * block->height * 4)
};
VkBuffer stagingBuffer;
VmaAllocation stagingBufferAllocation;
size_t stagingBufferSize = block->width * block->height * 4;
createBuffer(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&stagingBuffer, &stagingBufferAllocation);
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = block->textureImage,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT
};
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
// Copy image to buffer
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {block->width, block->height, 1}
};
vkCmdCopyImageToBuffer(
commandBuffer,
block->textureImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
stagingBuffer,
1,
®ion
);
// Transition image layout back
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkFence fence = getFence();
endSingleTimeCommands(commandBuffer, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Copy staging buffer back to CPU
void* data;
vmaMapMemory(vmaGetAllocator(), stagingBufferAllocation, &data);
memcpy(im.data, data, stagingBufferSize);
vmaUnmapMemory(vmaGetAllocator(), stagingBufferAllocation);
// Cleanup staging buffer
vmaDestroyBuffer(vmaGetAllocator(), stagingBuffer, stagingBufferAllocation);
return im;
}
$cc code {
struct WriteState {
uint8_t* buffer;
size_t* size;
};
void pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
struct WriteState* state = (struct WriteState*)png_get_io_ptr(png_ptr);
memcpy(state->buffer + *state->size, data, length);
*state->size += length;
}
}
$cc proc imageToPngBuffer {Image im size_t* outSize} uint8_t* {
size_t bufferSize = im.width * im.height * im.components * 2; // max size estimate
uint8_t* buffer = malloc(bufferSize);
*outSize = 0;
png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_w) {
free(buffer);
return NULL;
}
png_infop info_w = png_create_info_struct(png_w);
if (!info_w) {
png_destroy_write_struct(&png_w, NULL);
free(buffer);
return NULL;
}
struct WriteState state = {
.buffer = buffer,
.size = outSize
};
png_set_write_fn(png_w, &state, pngWriteCallback, NULL);
if (im.components == 4) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else if (im.components == 3) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_destroy_write_struct(&png_w, &info_w);
free(buffer);
return NULL;
}
png_bytep* row_pointers = malloc(sizeof(png_bytep) * im.height);
for (int y = 0; y < im.height; y++) {
row_pointers[y] = im.data + y * im.bytesPerRow;
}
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
png_destroy_write_struct(&png_w, &info_w);
*outSize = bufferSize;
return buffer;
}
$cc proc copyAllTexturesFromGpu {} Jim_Obj* {
Jim_Obj* ret = Jim_NewListObj(interp, NULL, 0);
for (int i = 0; i < getMaxTextures(); i++) {
if (getGpuTexture(i)->alive) {
Image im = copyTextureFromGpu(i);
size_t pngSize;
uint8_t* pngData = imageToPngBuffer(im, &pngSize);
Jim_ListAppendElement(interp, ret, Jim_ObjPrintf("Image %d (%d x %d)", i, im.width, im.height));
Jim_ListAppendElement(interp, ret, Jim_NewStringObj(interp, (char*)pngData, pngSize));
free(pngData);
free(im.data);
}
}
return ret;
}
set texturesLib [$cc compile]
$texturesLib texturesLibInit
Wish the web server handles route {/textures} with handler {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
}
}} with environment {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {drawLib <C:cfile7Rjpvq>} {}}
when the GPU texture library is /gpuTextureLib/ \n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$c (
[ m18000:0 (s27448:0 s27451:0) ]
)when the GPU texture library is /gpuTextureLib/ \n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n with environment {{this builtin-programs/gpu/pipelines.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {}}
when the GPU texture library is /gpuTextureLib/ {When the GPU pipeline library is /pipelineLib/ & the (
[ m18001:0 (s23869:0) ]
)when the GPU texture library is /gpuTextureLib/ {When the GPU pipeline library is /pipelineLib/ & the GPU pipeline compiler library is /pipelineCompilerLib/ \n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n} with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {}}
when the GPU texture library is /gpuTextureLib/ \n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ (
[ m20734:0 (s31107:0 s31108:0 s31109:0 s31110:0 s31111:0 s31112:0 s31113:0) ]
)when the GPU texture library is /gpuTextureLib/ \n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {}}
when the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cfla (
[ m23442:0 (s33520:0) ]
)when the GPU texture library is /gpuTextureLib/ {
set cc [C]
$cc endcflags -lpng
$cc cflags -I./vendor
$cc endcflags $vmaDll
$cc include <png.h>
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
#include "vk_mem_alloc.h"
VmaAllocator vmaGetAllocator();
VkDevice device;
}
# HACK: to make gpuLib extend properly
$cc typedef {struct PushConstantsEncoder} PushConstantsEncoder
$cc typedef {struct Pipeline} Pipeline
$cc typedef {struct VmaAllocation_T*} VmaAllocation
$cc argtype VmaAllocation {
VmaAllocation $argname;
sscanf(Jim_String($obj), "(VmaAllocation) %p", &$argname);
}
$cc rtype VmaAllocation {
char buf[100];
snprintf(buf, 100, "(VmaAllocation) %p", $rvalue);
$robj = Jim_NewStringObj(interp, buf, -1);
}
$cc extend $gpuLib
$cc extend $imageLib
$cc extend $gpuTextureLib
$cc proc texturesLibInit {} void {
volkInitialize();
volkLoadInstanceOnly(*instance_ptr());
device = *device_ptr();
volkLoadDevice(device);
}
$cc proc copyTextureFromGpu {GpuTextureHandle han} Image {
GpuTextureBlock* block = getGpuTexture(han);
if (!block->alive) {
return (Image){0};
}
Image im = {
.width = block->width,
.height = block->height,
.components = 4, // HACK: hard-coded for now
.bytesPerRow = block->width * 4,
.data = malloc(block->width * block->height * 4)
};
VkBuffer stagingBuffer;
VmaAllocation stagingBufferAllocation;
size_t stagingBufferSize = block->width * block->height * 4;
createBuffer(stagingBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&stagingBuffer, &stagingBufferAllocation);
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = block->textureImage,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1,
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT
};
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
// Copy image to buffer
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.imageSubresource.mipLevel = 0,
.imageSubresource.baseArrayLayer = 0,
.imageSubresource.layerCount = 1,
.imageOffset = {0, 0, 0},
.imageExtent = {block->width, block->height, 1}
};
vkCmdCopyImageToBuffer(
commandBuffer,
block->textureImage,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
stagingBuffer,
1,
®ion
);
// Transition image layout back
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkFence fence = getFence();
endSingleTimeCommands(commandBuffer, fence);
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
// Copy staging buffer back to CPU
void* data;
vmaMapMemory(vmaGetAllocator(), stagingBufferAllocation, &data);
memcpy(im.data, data, stagingBufferSize);
vmaUnmapMemory(vmaGetAllocator(), stagingBufferAllocation);
// Cleanup staging buffer
vmaDestroyBuffer(vmaGetAllocator(), stagingBuffer, stagingBufferAllocation);
return im;
}
$cc code {
struct WriteState {
uint8_t* buffer;
size_t* size;
};
void pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) {
struct WriteState* state = (struct WriteState*)png_get_io_ptr(png_ptr);
memcpy(state->buffer + *state->size, data, length);
*state->size += length;
}
}
$cc proc imageToPngBuffer {Image im size_t* outSize} uint8_t* {
size_t bufferSize = im.width * im.height * im.components * 2; // max size estimate
uint8_t* buffer = malloc(bufferSize);
*outSize = 0;
png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_w) {
free(buffer);
return NULL;
}
png_infop info_w = png_create_info_struct(png_w);
if (!info_w) {
png_destroy_write_struct(&png_w, NULL);
free(buffer);
return NULL;
}
struct WriteState state = {
.buffer = buffer,
.size = outSize
};
png_set_write_fn(png_w, &state, pngWriteCallback, NULL);
if (im.components == 4) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else if (im.components == 3) {
png_set_IHDR(png_w, info_w, im.width, im.height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_destroy_write_struct(&png_w, &info_w);
free(buffer);
return NULL;
}
png_bytep* row_pointers = malloc(sizeof(png_bytep) * im.height);
for (int y = 0; y < im.height; y++) {
row_pointers[y] = im.data + y * im.bytesPerRow;
}
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
png_destroy_write_struct(&png_w, &info_w);
*outSize = bufferSize;
return buffer;
}
$cc proc copyAllTexturesFromGpu {} Jim_Obj* {
Jim_Obj* ret = Jim_NewListObj(interp, NULL, 0);
for (int i = 0; i < getMaxTextures(); i++) {
if (getGpuTexture(i)->alive) {
Image im = copyTextureFromGpu(i);
size_t pngSize;
uint8_t* pngData = imageToPngBuffer(im, &pngSize);
Jim_ListAppendElement(interp, ret, Jim_ObjPrintf("Image %d (%d x %d)", i, im.width, im.height));
Jim_ListAppendElement(interp, ret, Jim_NewStringObj(interp, (char*)pngData, pngSize));
free(pngData);
free(im.data);
}
}
return ret;
}
set texturesLib [$cc compile]
$texturesLib texturesLibInit
Wish the web server handles route {/textures} with handler {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
}
} with environment {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {drawLib <C:cfile7Rjpvq>} {} {vmaDll /tmp/cfilequ8HAs.so} {}}
when the calibration measurements are /measurements/ {
set m_tag [string trimright [dict get $mea (
[ m924:0 (s1604:0 s1605:0) ]
)when the calibration measurements are /measurements/ {
set m_tag [string trimright [dict get $measurements tagSideLength] mm]
set m_left [string trimright [dict get $measurements left] mm]
set m_bottom [string trimright [dict get $measurements bottom] mm]
# Derive a PostScript CTM that maps calibrated space (origin at
# paper bottom-left, 1 unit = 1 physical point = 25.4/72 mm) to
# the printer's raw PS coordinate space.
#
# The calibration board was printed unmediated, so its PS coords
# are the printer's raw coords. The measurement lines were drawn
# at PS positions measureLeft and measureTop; the tag inner side
# was tagInnerSideLength PS points. From the physical measurements
# (in mm) we can recover the printer's scale and origin offset.
set scale [expr {25.4 * $tagInnerSideLength / (72.0 * $m_tag)}]
set tx [expr {$measureLeft - $m_left * $tagInnerSideLength / $m_tag}]
set ty [expr {$measureTop - $m_bottom * $tagInnerSideLength / $m_tag}]
Claim the calibrated print scale is $scale
Claim the calibrated print translation is [list $tx $ty]
} with environment {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70}}
when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ & t (
[ m724:0 (s1116:0) ]
)when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ & the calibration poses max is /calibrationPosesMax/ & the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ & /nobody/ claims a calibration from camera /camera/ to display /display/ is /anything/ & the calibration refiner is /refineCalibration/ \n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det ^setCameraToProjectorExtrinsics {{modelLib calibrationVar calibrationPoses} \n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n {builtin-programs/calibrate/calibrate.folk 543}} ^unrefinedCalibrateCameraAndProjector {{modelLib matLib calibrationPoses} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/calibrate.folk 613}} ^processHomography {H \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n {builtin-programs/calibrate/calibrate.folk 413}} ^zhangUnrefinedCalibrate {{name width height Hs} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n {builtin-programs/calibrate/calibrate.folk 452}}}}
when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ \n\ (
[ m1047:0 (s1832:0) ]
)when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ \n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n} with environment {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {}}
when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ & / (
[ m23570:0 (s31214:0) ]
)when the calibration model library is /modelLib/ {When the calibration matrix library is /matLib/ & /someone/ wishes to calibrate camera {$camera} to display {$display} using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {display monitor displayWidth 4096 displayHeight 2160} {} {makeAprilTagDetector {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}}}}}} {} {jpegLib <C:cfileZXB3iE>} {}}
when the calibration model library is /modelLib/ {When /someone/ wishes to draw calibration model /mo (
[ m23574:0 (s31221:0) ]
)when the calibration model library is /modelLib/ {When /someone/ wishes to draw calibration model /model/ using model-to-display homography /H_modelToDisplay/ with message /calibrationMessage/ \n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/draw-model.folk} {} {} {display monitor displayWidth 4096 displayHeight 2160} {} {matLib <C:cfile5JsRBY>} {}}
when the calibration matrix library is /matLib/ {When the calibration poses max is /calibrationPosesM (
[ m4484:0 (s6282:0) ]
)when the calibration matrix library is /matLib/ {When the calibration poses max is /calibrationPosesMax/ & the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ & /nobody/ claims a calibration from camera /camera/ to display /display/ is /anything/ & the calibration refiner is /refineCalibration/ \n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det ^setCameraToProjectorExtrinsics {{modelLib calibrationVar calibrationPoses} \n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n {builtin-programs/calibrate/calibrate.folk 543}} ^unrefinedCalibrateCameraAndProjector {{modelLib matLib calibrationPoses} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/calibrate.folk 613}} ^processHomography {H \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n {builtin-programs/calibrate/calibrate.folk 413}} ^zhangUnrefinedCalibrate {{name width height Hs} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n {builtin-programs/calibrate/calibrate.folk 452}}} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {}}
when the calibration matrix library is /matLib/ \n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set (
[ m4485:0 (s6285:0 s6288:0 s6291:0 s6292:0 s6293:0) ]
)when the calibration matrix library is /matLib/ \n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n with environment {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {}}
when the calibration matrix library is /matLib/ {When /someone/ wishes to calibrate camera {$camera} (
[ m23571:0 (s31217:0) ]
)when the calibration matrix library is /matLib/ {When /someone/ wishes to calibrate camera {$camera} to display {$display} using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {display monitor displayWidth 4096 displayHeight 2160} {} {makeAprilTagDetector {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}}}}}} {} {jpegLib <C:cfileZXB3iE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {}}
when the calibration matrix library is /matLib/ {When the calibration model library is /modelLib/ & / (
[ m23573:0 (s31220:0) ]
)when the calibration matrix library is /matLib/ {When the calibration model library is /modelLib/ & /someone/ wishes to draw calibration model /model/ using model-to-display homography /H_modelToDisplay/ with message /calibrationMessage/ \n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/draw-model.folk} {} {} {display monitor displayWidth 4096 displayHeight 2160} {}}
when the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ {
# H (
[ m1053:0 (s1850:0 s1854:0) ]
)when the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ {
# Hold reporting info for the Web page.
set posesReport [subst {
<p>Poses:</p><ol>
[join [lmap pose $calibrationPoses {
set width [dict get $pose cameraWidth]
set height [dict get $pose cameraHeight]
subst {
<li style="padding-bottom: 1em">
RMSE [dict getdef $pose rmse (unavailable)]
<div style="position: relative; width: 300px; height: [expr {(300.0 / $width) * $height}]px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: [expr {(300.0 / $width) * $height}]px"
src="/calibration-poses/[dict get $pose imageName]">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: [expr {(300.0 / $width) * $height}]px; pointer-events: none"
viewBox="0 0 [dict get $pose cameraWidth] [dict get $pose cameraHeight]">
[join [lmap det [dict values [dict get $pose tags]] {
set points [dict get $det p]
set coords [lmap point $points {
format "%g,%g" [lindex $point 0] [lindex $point 1]
}]
lappend coords [lindex $coords 0]
set id [dict get $det id]
subst {
<polyline points="$coords" fill="none" stroke="green" stroke-width="3" />
<text x="[lindex $points 0 0]" y="[lindex $points 0 1]" fill="green" font-size="12">${id}</text>
}
}] "\n"]
</svg>
</div>
</li>
}
}] \n]
[string repeat {<li>Not detected yet</li>} [- 10 [llength $calibrationPoses]]]
</ol>
}]
When /nobody/ claims a calibration from camera /camera/ to display /display/ is /anything/ {
Claim the calibration report is $posesReport
}
When a calibration from camera /camera/ to display /display/ is /calibration/ {
set calibrationReport "$posesReport
<p>Calibration:</p><pre>
Camera intrinsics --------
[join [lmap {k v} [dict get $calibration camera intrinsics] {list $k $v}] \n]
Camera RMSE [dict getdef $calibration camera rmse (unavailable)]
Projector intrinsics -----
[join [lmap {k v} [dict get $calibration projector intrinsics] {list $k $v}] \n]
Projector RMSE [dict getdef $calibration projector rmse (unavailable)]
----
Stereo RMSE [dict getdef $calibration rmse (unavailable)]
</pre>"
Claim the calibration report is $calibrationReport
}
} with environment {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}}}
when the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ {When /no (
[ m4489:0 (s6294:0) ]
)when the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ {When /nobody/ claims a calibration from camera {$camera} to display {$display} is /anything/ & the calibration refiner is /refineCalibration/ \n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det ^setCameraToProjectorExtrinsics {{modelLib calibrationVar calibrationPoses} \n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n {builtin-programs/calibrate/calibrate.folk 543}} ^unrefinedCalibrateCameraAndProjector {{modelLib matLib calibrationPoses} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/calibrate.folk 613}} ^processHomography {H \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n {builtin-programs/calibrate/calibrate.folk 413}} ^zhangUnrefinedCalibrate {{name width height Hs} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n {builtin-programs/calibrate/calibrate.folk 452}}} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {} {calibrationPosesMax 10} {}}
when the calibration poses max is /calibrationPosesMax/ {When the calibration poses from camera /came (
[ m4487:0 (s6286:0) ]
)when the calibration poses max is /calibrationPosesMax/ {When the calibration poses from camera /camera/ to display /display/ are /calibrationPoses/ & /nobody/ claims a calibration from camera /camera/ to display /display/ is /anything/ & the calibration refiner is /refineCalibration/ \n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det ^setCameraToProjectorExtrinsics {{modelLib calibrationVar calibrationPoses} \n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n {builtin-programs/calibrate/calibrate.folk 543}} ^unrefinedCalibrateCameraAndProjector {{modelLib matLib calibrationPoses} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/calibrate.folk 613}} ^processHomography {H \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n {builtin-programs/calibrate/calibrate.folk 413}} ^zhangUnrefinedCalibrate {{name width height Hs} \n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n {builtin-programs/calibrate/calibrate.folk 452}}} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {}}
when the codeToPostScript is /codeToPostScript/ \n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ h (
[ m1048:0 (s1835:0 s1836:0 s1837:0) ]
)when the codeToPostScript is /codeToPostScript/ \n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n with environment {{this builtin-programs/calibrate/calibrate-page.folk} {} {}}
when the codeToPostScript is /codeToPostScript/ {When /someone/ wishes editor /editor/ has a print pr (
[ m1046:0 (s1831:0) ]
)when the codeToPostScript is /codeToPostScript/ {When /someone/ wishes editor /editor/ has a print preview & editor /editor/ has selected program /program/ \n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n} with environment {{this builtin-programs/editor/print-editor.folk} {} {^editorToPrintOptions {editor \n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n {builtin-programs/editor/print-editor.folk 1}}}}
when the editor utils library is /utils/ \n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ edit (
[ m802:0 (s1233:0) ]
)when the editor utils library is /utils/ \n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/editor/draw-editor.folk} {} {}}
when the editor utils library is /utils/ \n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \ (
[ m829:0 (s1275:0 s1276:0 s1277:0 s1278:0 s1279:0 s1280:0) ]
)when the editor utils library is /utils/ \n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {}}
when the migration is complete {
set namespaces [glob -nocomplain $dataDirectory/*/]
foreach (
[ m919:0 (s1564:0 s1565:0) ]
)when the migration is complete {
set namespaces [glob -nocomplain $dataDirectory/*/]
foreach namespace $namespaces {
set namespaceName [file tail $namespace]
Wish to deserialize namespace $namespaceName with directory $namespace
}
} with environment {{this builtin-programs/saving/saving.folk} {} {dataDirectory /home/folk/folk-data}}
when the hold save directory is /holdDirectory/ {When the program save directory is /programDirectory (
[ m838:0 (s1292:0) ]
[ m839:0 (s1293:0) ]
)when the hold save directory is /holdDirectory/ {When the program save directory is /programDirectory/ & saving is ready \n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n} with environment {{this builtin-programs/saving/migrate.folk} {} {}}
when the hold save directory is /holdDirectory/ \n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key (
[ m916:0 (s1292:0) ]
[ m917:0 (s1561:0 s1562:0) ]
)when the hold save directory is /holdDirectory/ \n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n with environment {{this builtin-programs/saving/save-holds.folk} {} {savedHoldsLib <C:cfilecAUX4H> cc ::<reference.<C______>.00000000000000000006>}}
when the contour library is /contourLib/ {When /someone/ wishes /p/ has contours with /...opts/ \n\ \ (
[ m940:0 (s1636:0) ]
)when the contour library is /contourLib/ {When /someone/ wishes /p/ has contours with /...opts/ \n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n} with environment {{this builtin-programs/recognition/contours.folk} {} {}}
when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /proj/ has width (
[ m1393:0 (s2255:0) ]
)when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /proj/ has width /projWidth/ height /projHeight/ & display /proj/ has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /disp/ has width (
[ m1394:0 (s2258:0) ]
)when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n} with environment {{this builtin-programs/points-at.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /disp/ has width (
[ m1396:0 (s2260:0) ]
)when the pose library is /poseLib/ {When the quad changer is /quadChange/ & display /disp/ has width /displayWidth/ height /displayHeight/ & display /disp/ has intrinsics /displayIntrinsics/ & /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the pose library is /poseLib/ {When the quad changer is /quadChange/ & /someone/ wishes /p/ has (
[ m1399:0 (s2263:0) ]
)when the pose library is /poseLib/ {When the quad changer is /quadChange/ & /someone/ wishes /p/ has camera slice & camera /cam/ has intrinsics /cameraIntrinsics/ & camera /cam/ has frame /frame/ at timestamp /timestamp/ & /p/ has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when the pose library is /poseLib/ {When the quad library is /quadLib/ & the quad changer is /quadCha (
[ m6536:944 (s53061:1173) ]
)when the pose library is /poseLib/ {When the quad library is /quadLib/ & the quad changer is /quadChange/ & 54 has resolved geometry /geom/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {}}
when the changer from space /sourceSpace/ to space /targetSpace/ is /changer/ {
$collectLib S (
[ m1402:0 () ]
[ m1403:0 () ]
)when the changer from space /sourceSpace/ to space /targetSpace/ is /changer/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {the changer from space /sourceSpace/ to space /targetSpace/ is /changer/} settle 0ms} {settleMs 0 settleNs 0}}
when the AprilTag detector maker is /makeAprilTagDetector/ {When the jpeg library is /jpegLib/ & the (
[ m23568:0 (s31212:0) ]
)when the AprilTag detector maker is /makeAprilTagDetector/ {When the jpeg library is /jpegLib/ & the calibration model library is /modelLib/ & the calibration matrix library is /matLib/ & /someone/ wishes to calibrate camera {$camera} to display {$display} using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {display monitor displayWidth 4096 displayHeight 2160} {}}
when the audio library is /audioLib/ {When /someone/ wishes to play audio /sound/ {
# Check if t (
[ m31822:2 (s1438:3) ]
)when the audio library is /audioLib/ {When /someone/ wishes to play audio /sound/ {
# Check if the sound file exists in the user-programs/$hostname/sounds directory
# or in the working directory's assets/sounds subdirectory. Otherwise, assume
# it's an absolute path.
proc resolveSoundPath {filename} {
set scriptDir [file dirname [info script]]
set projectRoot [pwd]
set hostname [info hostname]
set path "$projectRoot/user-programs/$hostname/audio/$filename"
if {[file exists $path]} { return $path }
set path "$projectRoot/audio/$filename"
if {[file exists $path]} { return $path }
# treat as an absolute path
return $filename
}
set path [resolveSoundPath $sound]
if {![file exists $path]} {
puts stderr "audio: File not found '$path'"
return
}
set handle [$audioLib playSound $path]
if {$handle == 0} {
puts stderr "audio: Failed to play '$path'"
return
}
On unmatch {
puts "audio: stopping audio '$path'"
$audioLib audioStop $handle
}
}} with environment {{this builtin-programs/audio.folk} {} {success 1 audioLib <C:cfileaDB4QL> cc ::<reference.<C______>.00000000000000000002>}}
when the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGe (
[ m23376:1062 (s14710:1222 s14712:1223 s14713:1259 s14714:1259 s14715:1222 s14716:1223 s14719:1258 s14720:1258 s14721:1259 s14722:1259 s14723:1258 s14724:1259 s14725:1258) ]
)when the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelle ()when the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {}}
when the animation toy's fps is /FPS/ {When the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ ()when the animation toy's fps is /FPS/ {When the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {}}
when When\ when\ the\ collected\ results\ for\ /clause/\ are\ /resultsVar/\ \\\n\ \ \ \ \ \ \ \ \ \ / (
[ m19:0 (s45:0 s49:0 s315:0 s316:0) ]
)when When\ when\ the\ collected\ results\ for\ /clause/\ are\ /resultsVar/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ to\ collect\ results\ for\ \$clause\ with\ settle\ 0ms\n\}\nWhen\ when\ the\ collected\ results\ for\ /clause/\ with\ settle\ /settle/\ are\ /resultsVar/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ to\ collect\ results\ for\ \$clause\ with\ settle\ \$settle\n\}\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I.\n\$cc\ include\ <string.h>\n\$cc\ include\ <pthread.h>\n\$cc\ include\ \"trie.h\"\n\$cc\ include\ \"db.h\"\n\$cc\ code\ \{\n\ \ \ \ extern\ Db*\ db\;\n\ \ \ \ extern\ Clause*\ jimObjToClause(Jim_Interp*\ interp,\ Jim_Obj*\ obj)\;\n\ \ \ \ extern\ Statement*\ HoldStatementGlobally(const\ char\ *key,\ double\ version,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Clause\ *clause,\ long\ keepMs,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *destructorCode,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *sourceFileName,\ int\ sourceLineNumber)\;\n\ \ \ \ extern\ Statement*\ HoldStatementGloballyAcquiring(const\ char\ *key,\ double\ version,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Clause\ *clause,\ long\ keepMs,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *destructorCode,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *sourceFileName,\ int\ sourceLineNumber)\;\n\ \ \ \ extern\ Clause*\ claimizeClause(Clause*\ clause)\;\n\n\ \ \ \ typedef\ struct\ EnvironmentBinding\ \{\n\ \ \ \ \ \ \ \ char\ name\[100\]\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ value\;\n\ \ \ \ \}\ EnvironmentBinding\;\n\ \ \ \ typedef\ struct\ Environment\ \{\n\ \ \ \ \ \ \ \ int\ nBindings\;\n\ \ \ \ \ \ \ \ EnvironmentBinding\ bindings\[\]\;\n\ \ \ \ \}\ Environment\;\n\ \ \ \ extern\ Environment*\ clauseUnify(Jim_Interp*\ interp,\ Clause*\ a,\ Clause*\ b)\;\n\n\ \ \ \ typedef\ struct\ Collect\ \{\n\ \ \ \ \ \ \ \ char*\ _Atomic\ patternStr\;\n\ \ \ \ \ \ \ \ uint64_t\ _Atomic\ collectAtTime\;\n\ \ \ \ \}\ Collect\;\n\n\ \ \ \ #define\ COLLECTS_MAX\ 1000\n\ \ \ \ Collect\ collects\[COLLECTS_MAX\]\;\n\ \ \ \ pthread_mutex_t\ collectsMutex\;\n\n\ \ \ \ static\ int64_t\ timestamp_get(clockid_t\ clk_id)\ \{\n\ \ \ \ \ \ \ \ //\ Returns\ timestamp\ in\ nanoseconds.\n\ \ \ \ \ \ \ \ struct\ timespec\ ts\;\n\ \ \ \ \ \ \ \ if\ (clock_gettime(clk_id,\ &ts))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ perror(\"can't\ even\ get\ the\ time\ :'-(\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ (int64_t)ts.tv_sec\ *\ 1000000000\ +\ (int64_t)ts.tv_nsec\;\n\ \ \ \ \}\n\n\ \ \ \ char*\ makeCollectKey(Jim_Obj*\ patternObj)\ \{\n\ \ \ \ \ \ \ \ const\ char\ COLLECT\[\]\ =\ \"collect\ \"\;\n\ \ \ \ \ \ \ \ int\ collectLen\ =\ sizeof(COLLECT)\ -\ 1\;\n\n\ \ \ \ \ \ \ \ int\ keyLen\ =\ Jim_Length(patternObj)\;\n\ \ \ \ \ \ \ \ char\ *collectKey\ =\ malloc(collectLen\ +\ keyLen\ +\ 1)\;\n\ \ \ \ \ \ \ \ memcpy(collectKey,\ COLLECT,\ collectLen)\;\n\ \ \ \ \ \ \ \ memcpy(collectKey\ +\ collectLen,\ Jim_String(patternObj),\ keyLen\ +\ 1)\;\n\ \ \ \ \ \ \ \ return\ collectKey\;\n\ \ \ \ \}\n\n\ \ \ \ Term*\ jimObjToTerm(Jim_Obj*\ obj)\ \{\n\ \ \ \ \ \ \ \ int\ len\;\ const\ char*\ s\;\n\ \ \ \ \ \ \ \ s\ =\ Jim_GetString(obj,\ &len)\;\n\ \ \ \ \ \ \ \ return\ termNew(s,\ len)\;\n\ \ \ \ \}\n\n\ \ \ \ int\ _Atomic\ version\ =\ 0\;\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_init(&collectsMutex,\ NULL)\;\n\}\n\$cc\ proc\ Recollect!\ \{Jim_Obj*\ patternObj\ bool\ isAtomically\}\ void\ \{\n\ \ \ \ //\ First,\ query\ for\ collect\ patterns.\n\ \ \ \ Clause*\ collectorPattern\ =\ clauseNew(10)\;\n\ \ \ \ collectorPattern->terms\[0\]\ =\ termNew(\"/someone/\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[1\]\ =\ termNew(\"wishes\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[2\]\ =\ termNew(\"to\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[3\]\ =\ termNew(\"collect\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[4\]\ =\ termNew(\"results\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[5\]\ =\ termNew(\"for\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[6\]\ =\ jimObjToTerm(patternObj)\;\n\ \ \ \ collectorPattern->terms\[7\]\ =\ termNew(\"with\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[8\]\ =\ termNew(\"settle\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[9\]\ =\ termNew(\"/settle/\",\ -1)\;\n\n\ \ \ \ char*\ collectKey\ =\ makeCollectKey(patternObj)\;\n\n\ \ \ \ ResultSet*\ collectorsSet\ =\ dbQuery(db,\ collectorPattern)\;\n\ \ \ \ if\ (collectorsSet->nResults\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Clause*\ emptyClause\ =\ clauseNew(0)\;\n\ \ \ \ \ \ \ \ HoldStatementGlobally(collectKey,\ version++,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emptyClause,\ 0,\ NULL,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(interp,\ patternObj)\;\n\n\ \ \ \ \ \ \ \ ResultSet*\ rs\ =\ dbQuery(db,\ pattern)\;\n\ \ \ \ \ \ \ \ size_t\ unclaimizedNResults\ =\ rs->nResults\;\n\n\ \ \ \ \ \ \ \ Clause*\ claimizedPattern\ =\ claimizeClause(pattern)\;\n\ \ \ \ \ \ \ \ if\ (claimizedPattern\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ResultSet*\ rs1\ =\ dbQuery(db,\ claimizedPattern)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ rs\ =\ realloc(rs,\ SIZEOF_RESULTSET(rs->nResults\ +\ rs1->nResults))\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ rs1->nResults\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rs->results\[rs->nResults\ +\ i\]\ =\ rs1->results\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ rs->nResults\ +=\ rs1->nResults\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(rs1)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Now\ acquire\ all\ the\ statements\ in\ rs,\ unify\ each\ statement's\n\ \ \ \ \ \ \ \ //\ clause\ with\ the\ pattern,\ and\ build\ up\ a\ results\ Jim\ object.\n\n\ \ \ \ \ \ \ \ Statement**\ resultStmts\ =\ malloc(sizeof(Statement*)\ *\ rs->nResults)\;\n\ \ \ \ \ \ \ \ int\ resultStmtsCount\ =\ 0\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultsObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ rs->nResults\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Statement*\ result\ =\ statementAcquire(db,\ rs->results\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (result\ ==\ NULL)\ \{\ continue\;\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ If\ `isAtomically`\ is\ on,\ then\ throw\ away\ any\n\ \ \ \ \ \ \ \ \ \ \ \ //\ statement\ that\ has\ an\ AtomicallyVersion\ _and_\ that\n\ \ \ \ \ \ \ \ \ \ \ \ //\ AtomicallyVersion\ isn't\ converged\ yet.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isAtomically\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementAtomicallyVersion(result)\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ !dbAtomicallyVersionHasConverged(statementAtomicallyVersion(result)))\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ fprintf(stderr,\ \"DISCARD\ %.100s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ clauseToString(statementClause(result)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ result)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ resultStmts\[resultStmtsCount++\]\ =\ result\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Environment*\ env\ =\ clauseUnify(interp,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i\ >=\ unclaimizedNResults\ ?\ claimizedPattern\ :\ pattern,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementClause(result))\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ envDict\[env->nBindings\ *\ 2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ env->nBindings\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ envDict\[j*2\]\ =\ Jim_NewStringObj(interp,\ env->bindings\[j\].name,\ -1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ envDict\[j*2+1\]\ =\ env->bindings\[j\].value\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *resultObj\ =\ Jim_NewDictObj(interp,\ envDict,\ env->nBindings\ *\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ resultsObj,\ resultObj)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(env)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (claimizedPattern\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(claimizedPattern)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ clauseFree(pattern)\;\n\ \ \ \ \ \ \ \ free(rs)\;\n\n\ \ \ \ \ \ \ \ //\ Note\ that\ at\ this\ point,\ we've\ still\ acquired\ all\ the\n\ \ \ \ \ \ \ \ //\ statements\ in\ rs.\ We\ need\ to\ hang\ onto\ them\ to\ inherit\n\ \ \ \ \ \ \ \ //\ their\ destructors.\n\n\ \ \ \ \ \ \ \ Clause*\ collectedClause\ =\ clauseNew(9)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[0\]\ =\ termNew(\"builtin-programs/collect.folk\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[1\]\ =\ termNew(\"claims\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[2\]\ =\ termNew(\"the\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[3\]\ =\ termNew(\"collected\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[4\]\ =\ termNew(\"results\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[5\]\ =\ termNew(\"for\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[6\]\ =\ jimObjToTerm(patternObj)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[7\]\ =\ termNew(\"are\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[8\]\ =\ jimObjToTerm(resultsObj)\;\n\ \ \ \ \ \ \ \ Jim_DecrRefCount(interp,\ resultsObj)\;\n\n\ \ \ \ \ \ \ \ Statement*\ stmt\ =\n\ \ \ \ \ \ \ \ \ \ \ \ HoldStatementGloballyAcquiring(collectKey,\ version++,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ collectedClause,\ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ Now\ inherit\ the\ destructors\ of\ all\ the\ statements\ in\ rs\n\ \ \ \ \ \ \ \ //\ into\ the\ new\ collection\ statement,\ and\ release\ all\ the\n\ \ \ \ \ \ \ \ //\ statements\ in\ rs.\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultStmtsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (stmt\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementInheritDestructors(stmt,\ resultStmts\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ FIXME:\ what\ to\ do\ if\ stmt\ is\ NULL?\n\n\ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ resultStmts\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(resultStmts)\;\n\n\ \ \ \ \ \ \ \ if\ (stmt\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dbInflightDecr(db,\ stmt)\;\n\ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ stmt)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ free(collectKey)\;\n\ \ \ \ clauseFree(collectorPattern)\;\n\ \ \ \ free(collectorsSet)\;\n\}\n#\ If\ the\ recollect\ doesn't\ have\ a\ settle\ time,\ we\ should\ recollect\n#\ immediately.\ If\ the\ recollect\ has\ a\ settle\ time,\ then\ we\ should\ bump\n#\ its\ next\ occurrence\ forward\ by\ the\ settle\ time.\n\$cc\ proc\ ScheduleRecollect!\ \{Jim_Obj*\ patternObj\ uint64_t\ settle\}\ void\ \{\n\ \ \ \ if\ (settle\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Recollect_(patternObj,\ false)\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ uint64_t\ now\ =\ timestamp_get(CLOCK_MONOTONIC)\;\n\ \ \ \ char*\ patternStr\ =\ strdup(Jim_String(patternObj))\;\n\n\ \ \ \ pthread_mutex_lock(&collectsMutex)\;\n\n\ \ \ \ int\ i\;\n\ \ \ \ for\ (i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ strcmp(collects\[i\].patternStr,\ patternStr)\ ==\ 0)\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ now\ +\ settle\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(patternStr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (i\ <\ COLLECTS_MAX)\ \{\ goto\ done\;\ \}\n\n\ \ \ \ for\ (i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].patternStr\ =\ patternStr\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ now\ +\ settle\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(i\ <\ COLLECTS_MAX)\;\n\n\ done:\n\ \ \ \ pthread_mutex_unlock(&collectsMutex)\;\n\}\n\$cc\ proc\ RunScheduledRecollects!\ \{\}\ void\ \{\n\ \ \ \ uint64_t\ now\ =\ timestamp_get(CLOCK_MONOTONIC)\;\n\n\ \ \ \ pthread_mutex_lock(&collectsMutex)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ <=\ now)\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ Recollect_(Jim_NewStringObj(interp,\ collects\[i\].patternStr,\ -1),\ true)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(collects\[i\].patternStr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].patternStr\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&collectsMutex)\;\n\}\nset\ collectLib\ \[\$cc\ compile\]\n\$collectLib\ init\n\n#\ FIXME:\ If\ there's\ not\ settlement\ for\ a\ while,\ we\ should\ just\ take\n#\ whatever\ we\ can\ get.\n\n#\ FIXME:\ If\ we're\ just\ booting\ now,\ we\ should\ sample\ whatever's\ in\n#\ place\ already.\n\nWhen\ /someone/\ wishes\ to\ collect\ results\ for\ /pattern/\ with\ settle\ /settle/\ \{\n\ \ \ \ if\ \{\[string\ match\ \{*ms\}\ \$settle\]\}\ \{\n\ \ \ \ \ \ \ \ set\ settleMs\ \[string\ range\ \$settle\ 0\ end-2\]\n\ \ \ \ \ \ \ \ set\ settleNs\ \[*\ \$settleMs\ 1000000\]\n\ \ \ \ \}\n\ \ \ \ When\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\n\ \ \ \ \ \ \ \ On\ unmatch\ \[list\ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\]\n\ \ \ \ \}\n\ \ \ \ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\n\ \ \ \ On\ unmatch\ \[list\ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\]\n\}\n\nWhen\ the\ internal\ time\ is\ /t/\ \{\n\ \ \ \ \$collectLib\ RunScheduledRecollects!\n\}\n with environment {{this builtin-programs/collect.folk}}
when when the collected results for /clause/ are /resultsVar/ /body/ with environment /e/ {
Wish (
[ m24:0 (s55:0) ]
[ m25:0 (s51:0) ]
[ m31:0 (s56:0) ]
[ m26:0 (s50:0) ]
[ m27:0 (s52:0) ]
[ m28:0 (s53:0) ]
[ m30:0 (s57:0) ]
[ m32:0 (s58:0) ]
[ m34:0 (s62:0) ]
[ m36:0 (s59:0) ]
[ m35:0 (s66:0) ]
[ m37:0 (s60:0) ]
[ m38:0 (s64:0) ]
[ m39:0 (s61:0) ]
[ m40:0 (s65:0) ]
[ m41:0 (s68:0) ]
[ m42:0 (s69:0) ]
[ m43:0 (s72:0) ]
[ m44:0 (s70:0) ]
[ m45:0 (s71:0) ]
[ m46:0 (s73:0) ]
[ m48:0 (s75:0) ]
[ m49:0 (s74:0) ]
[ m51:0 (s79:0) ]
[ m54:0 (s83:0) ]
[ m55:0 (s85:0) ]
[ m56:0 (s86:0) ]
[ m59:0 (s92:0) ]
[ m61:0 (s93:0) ]
[ m63:0 (s96:0) ]
[ m65:0 (s100:0) ]
[ m67:0 (s102:0) ]
[ m69:0 (s105:0) ]
[ m70:0 (s107:0) ]
[ m74:0 (s112:0) ]
[ m75:0 (s116:0) ]
[ m77:0 (s117:0) ]
[ m79:0 (s121:0) ]
[ m81:0 (s123:0) ]
[ m82:0 (s125:0) ]
[ m84:0 (s128:0) ]
[ m88:0 (s134:0) ]
[ m89:0 (s135:0) ]
[ m91:0 (s139:0) ]
[ m94:0 (s144:0) ]
[ m96:0 (s146:0) ]
[ m97:0 (s148:0) ]
[ m98:0 (s150:0) ]
[ m100:0 (s152:0) ]
[ m102:0 (s155:0) ]
[ m105:0 (s160:0) ]
[ m107:0 (s165:0) ]
[ m108:0 (s164:0) ]
[ m111:0 (s170:0) ]
[ m113:0 (s171:0) ]
[ m114:0 (s173:0) ]
[ m118:0 (s179:0) ]
[ m120:0 (s182:0) ]
[ m121:0 (s185:0) ]
[ m122:0 (s186:0) ]
[ m125:0 (s191:0) ]
[ m127:0 (s193:0) ]
[ m128:0 (s194:0) ]
[ m131:0 (s199:0) ]
[ m132:0 (s200:0) ]
[ m134:0 (s203:0) ]
[ m137:0 (s207:0) ]
[ m138:0 (s209:0) ]
[ m142:0 (s214:0) ]
[ m143:0 (s217:0) ]
[ m144:0 (s218:0) ]
[ m148:0 (s224:0) ]
[ m149:0 (s225:0) ]
[ m150:0 (s227:0) ]
[ m152:0 (s230:0) ]
[ m155:0 (s235:0) ]
[ m156:0 (s236:0) ]
[ m160:0 (s241:0) ]
[ m162:0 (s247:0) ]
[ m164:0 (s248:0) ]
[ m165:0 (s249:0) ]
[ m166:0 (s252:0) ]
[ m169:0 (s255:0) ]
[ m170:0 (s258:0) ]
[ m173:0 (s263:0) ]
[ m174:0 (s264:0) ]
[ m177:0 (s269:0) ]
[ m178:0 (s270:0) ]
[ m180:0 (s273:0) ]
[ m184:0 (s278:0) ]
[ m185:0 (s280:0) ]
[ m187:0 (s283:0) ]
[ m188:0 (s284:0) ]
[ m191:0 (s290:0) ]
[ m193:0 (s291:0) ]
[ m195:0 (s295:0) ]
[ m197:0 (s298:0) ]
[ m199:0 (s300:0) ]
[ m200:0 (s302:0) ]
[ m203:0 (s306:0) ]
[ m204:0 (s308:0) ]
[ m207:0 (s313:0) ]
[ m208:0 (s314:0) ]
[ m231:0 (s354:0) ]
[ m232:0 (s355:0) ]
[ m233:0 (s356:0) ]
[ m234:0 (s358:0) ]
[ m235:0 (s357:0) ]
[ m237:0 (s362:0) ]
[ m242:0 (s372:0) ]
[ m244:0 (s380:0) ]
[ m245:0 (s389:0) ]
[ m246:0 (s386:0) ]
[ m247:0 (s382:0) ]
[ m278:0 (s424:0) ]
[ m296:0 (s458:0) ]
[ m301:0 (s466:0) ]
[ m304:0 (s473:0) ]
[ m306:0 (s477:0) ]
[ m309:0 (s480:0) ]
[ m314:0 (s490:0) ]
[ m318:0 (s493:0) ]
[ m327:0 (s504:0) ]
[ m333:0 (s517:0) ]
[ m339:0 (s524:0) ]
[ m347:0 (s539:0) ]
[ m348:0 (s544:0) ]
[ m351:0 (s547:0) ]
[ m358:0 (s559:0) ]
[ m370:0 (s578:0) ]
[ m379:0 (s596:0) ]
[ m380:0 (s597:0) ]
[ m383:0 (s603:0) ]
[ m393:0 (s615:0) ]
[ m399:0 (s624:0) ]
[ m404:0 (s637:0) ]
[ m412:0 (s654:0) ]
[ m415:0 (s661:0) ]
[ m420:0 (s669:0) ]
[ m427:0 (s678:0) ]
[ m430:0 (s683:0) ]
[ m439:0 (s703:0) ]
[ m444:0 (s713:0) ]
[ m453:0 (s726:0) ]
[ m458:0 (s732:0) ]
[ m460:0 (s738:0) ]
[ m465:0 (s744:0) ]
[ m478:0 (s763:0) ]
[ m479:0 (s765:0) ]
[ m482:0 (s766:0) ]
[ m497:0 (s790:0) ]
[ m506:0 (s803:0) ]
[ m508:0 (s809:0) ]
[ m511:0 (s815:0) ]
[ m512:0 (s816:0) ]
[ m526:0 (s833:0) ]
[ m530:0 (s840:0) ]
[ m542:0 (s853:0) ]
[ m546:0 (s862:0) ]
[ m555:0 (s872:0) ]
[ m557:0 (s876:0) ]
[ m564:0 (s886:0) ]
[ m572:0 (s896:0) ]
[ m583:0 (s911:0) ]
[ m585:0 (s913:0) ]
[ m595:0 (s927:0) ]
[ m601:0 (s936:0) ]
[ m609:0 (s947:0) ]
[ m617:0 (s958:0) ]
[ m623:0 (s967:0) ]
[ m629:0 (s976:0) ]
[ m635:0 (s985:0) ]
[ m643:0 (s996:0) ]
[ m651:0 (s1007:0) ]
[ m659:0 (s1018:0) ]
[ m665:0 (s1028:0) ]
[ m669:0 (s1036:0) ]
[ m679:0 (s1046:0) ]
[ m684:0 (s1056:0) ]
[ m690:0 (s1065:0) ]
[ m696:0 (s1074:0) ]
[ m702:0 (s1083:0) ]
[ m708:0 (s1092:0) ]
[ m714:0 (s1100:0) ]
[ m720:0 (s1109:0) ]
[ m727:0 (s1121:0) ]
[ m733:0 (s1130:0) ]
[ m740:0 (s1141:0) ]
[ m747:0 (s1151:0) ]
[ m753:0 (s1160:0) ]
[ m761:0 (s1171:0) ]
[ m767:0 (s1180:0) ]
[ m774:0 (s1191:0) ]
[ m780:0 (s1200:0) ]
[ m786:0 (s1210:0) ]
[ m792:0 (s1219:0) ]
[ m798:0 (s1228:0) ]
[ m805:0 (s1238:0) ]
[ m811:0 (s1248:0) ]
[ m817:0 (s1258:0) ]
[ m823:0 (s1267:0) ]
[ m834:0 (s1287:0) ]
[ m844:0 (s1300:0) ]
[ m852:0 (s1311:0) ]
[ m858:0 (s1322:0) ]
[ m864:0 (s1333:0) ]
[ m870:0 (s1343:0) ]
[ m876:0 (s1356:0) ]
[ m882:0 (s1366:0) ]
[ m888:0 (s1376:0) ]
[ m894:0 (s1386:0) ]
[ m1025:0 (s1800:0) ]
[ m1027:0 (s1805:0) ]
[ m1033:0 (s1800:0) ]
[ m1063:0 (s1851:0) ]
[ m1097:0 (s1892:0) ]
[ m1400:0 (s2264:0) ]
[ m4495:0 (s6295:0) ]
[ m23659:0 (s31348:0) ]
[ m47950:639 (s15553:765) ]
[ m48152:643 (s15791:764) ]
[ m33930:725 (s14337:865) ]
[ m33936:727 (s14345:852) ]
[ m25655:915 (s2785:1088) ]
[ m25755:915 (s2896:1088) ]
[ m6393:988 (s52872:1175) ]
[ m6510:990 (s53023:1175) ]
[ m6580:989 (s53122:1174) ]
[ m6719:990 (s53277:1175) ]
[ m6727:990 (s53288:1174) ]
[ m6750:989 (s53314:1175) ]
[ m3058:1023 (s31838:1214) ]
[ m3089:1023 (s31882:1214) ]
[ m3371:1022 (s32222:1206) ]
[ m3374:1022 (s32227:1210) ]
[ m44358:1038 (s51509:1233) ]
[ m44365:1037 (s51515:1233) ]
[ m44372:1038 (s51526:1233) ]
[ m44376:1033 (s51534:1233) ]
[ m44638:1036 (s51834:1229) ]
[ m44683:1039 (s51883:1214) ]
[ m16188:1051 (s40285:1248) ]
[ m16192:1052 (s40289:1247) ]
[ m16198:1051 (s40294:1249) ]
[ m16202:1053 (s40297:1249) ]
[ m16434:1050 (s40582:1195) ]
[ m16463:1052 (s40615:1194) ]
[ m16464:1052 (s40616:1249) ]
[ m16473:1048 (s40625:1248) ]
[ m61802:1035 (s49323:1251) ]
[ m61815:1045 (s49340:1241) ]
[ m61824:1035 (s49349:1239) ]
[ m61855:1031 (s49340:1241) ]
[ m61857:1044 (s49385:1248) ]
[ m61881:975 (s49420:1239) ]
[ m61888:969 (s49425:1240) ]
[ m61895:974 (s49434:1249) ]
[ m61902:1054 (s49434:1249) ]
[ m61904:1055 (s49441:1250) ]
[ m61927:1054 (s49420:1239) ]
[ m61930:1052 (s49462:1252) ]
[ m62004:1055 (s49548:1252) ]
[ m24804:1057 () ]
[ m65096:1057 () ]
[ m65097:1057 () ]
[ m65131:1057 () ]
[ m17866:1055 (s28217:1245) ]
[ m17874:1058 (s28229:1254) ]
[ m17880:1058 (s28242:1254) ]
[ m17883:1058 (s28245:1248) ]
[ m23203:1061 (s14505:1248) ]
[ m23209:1061 (s14513:1259) ]
[ m23220:1061 (s14525:1259) ]
[ m23226:1062 (s14529:1260) ]
[ m23347:1062 (s14673:1259) ]
[ m23384:1060 (s14728:1258) ]
[ m23389:1040 (s14733:1258) ]
[ m23399:1040 (s14744:1258) ]
[ m23405:1062 (s14751:1260) ]
[ m23410:1059 (s14756:1221) ]
[ m23417:1040 (s14763:1259) ]
[ m23428:1061 (s14775:1222) ]
[ m23482:1060 (s14836:1257) ]
[ m23749:1062 (s15102:1255) ]
[ m23757:1062 (s15108:1260) ]
[ m23763:1060 (s15114:1260) ]
[ m23767:1062 (s15119:1260) ]
[ m24271:1036 () ]
[ m24274:1059 () ]
[ m24280:1057 () ]
[ m24288:1060 () ]
[ m24309:1061 () ]
[ m24313:1061 () ]
[ m24320:1059 () ]
[ m24323:1042 () ]
[ m25398:1062 () ]
[ m25404:1062 () ]
[ m25417:1062 () ]
[ m25428:1061 () ]
[ m57107:768 () ]
[ m57112:1063 () ]
[ m57119:768 () ]
[ m57125:1043 () ]
[ m12164:1064 () ]
[ m12170:1064 () ]
[ m12173:1062 () ]
[ m12178:1064 () ]
[ m12472:1063 () ]
[ m12481:1063 () ]
[ m12489:1064 () ]
[ m12496:1059 () ]
[ m20131:1064 () ]
[ m20139:1062 () ]
[ m20144:1064 () ]
[ m20150:1063 () ]
[ m25176:1063 () ]
[ m25181:1063 () ]
[ m25187:1064 () ]
[ m25192:1059 () ]
[ m25308:1060 () ]
[ m25314:1060 () ]
[ m25320:1062 () ]
[ m25329:1061 () ]
[ m25479:1061 () ]
[ m25486:1064 () ]
[ m25490:1062 () ]
[ m25491:1064 () ]
[ m25497:1064 () ]
[ m25499:1064 () ]
[ m25505:1064 () ]
[ m25509:1062 () ]
[ m29754:1064 () ]
[ m29759:1056 () ]
[ m29762:1064 () ]
[ m29768:1056 () ]
[ m34712:1064 () ]
[ m34723:1064 () ]
[ m34731:1064 () ]
[ m34740:1064 () ]
[ m40448:1064 () ]
[ m40453:1064 () ]
[ m40458:1064 () ]
[ m40464:1064 () ]
[ m47702:1058 (s64450:987) ]
[ m47709:1058 (s64464:1258) ]
[ m47772:1063 (s64537:1262) ]
[ m47782:1063 (s64546:1261) ]
[ m47876:1064 () ]
[ m47882:1063 () ]
[ m47890:1063 () ]
[ m47900:1064 () ]
[ m53651:1064 () ]
[ m53657:1064 () ]
[ m53666:1064 () ]
[ m53675:1063 () ]
[ m60522:1044 (s15412:1259) ]
[ m60527:1043 (s15417:1261) ]
[ m60531:1034 (s15421:1259) ]
[ m60537:1064 (s15428:1257) ]
[ m61129:1064 () ]
[ m61137:1055 () ]
[ m61142:1055 () ]
[ m61148:1063 () ]
[ m61428:1064 () ]
[ m61433:1063 () ]
[ m61437:1064 () ]
[ m61444:1063 () ]
[ m61464:1064 () ]
[ m61471:1064 () ]
[ m61476:1060 () ]
[ m61484:1061 () ]
[ m10495:1061 () ]
[ m10503:1064 () ]
[ m10511:1063 () ]
[ m10519:1064 () ]
[ m10731:1065 () ]
[ m10737:1063 () ]
[ m10740:1065 () ]
[ m10745:1061 () ]
[ m10774:1057 () ]
[ m10781:1065 () ]
[ m10791:1055 () ]
[ m10797:1055 () ]
[ m11030:1065 () ]
[ m11034:1065 () ]
[ m11038:1064 () ]
[ m11043:1065 () ]
[ m13839:1065 () ]
[ m13844:1065 () ]
[ m13848:1064 () ]
[ m13854:1062 () ]
[ m29757:1065 () ]
[ m29764:1057 () ]
[ m29769:1060 () ]
[ m29772:1052 () ]
[ m29777:1057 () ]
[ m29778:1059 () ]
[ m29789:1064 () ]
[ m29794:1063 () ]
[ m30073:1065 () ]
[ m30081:1064 () ]
[ m30082:1065 () ]
[ m30088:1065 () ]
[ m30106:1065 () ]
[ m30113:1064 () ]
[ m30119:1064 () ]
[ m30124:1064 () ]
[ m40577:1064 () ]
[ m40580:1058 () ]
[ m40590:1064 () ]
[ m40597:1060 () ]
[ m43956:1065 () ]
[ m43961:1065 () ]
[ m43971:1059 () ]
[ m43977:1065 () ]
[ m48881:1063 () ]
[ m48890:1065 () ]
[ m48896:1064 () ]
[ m48903:1064 () ]
[ m49744:1064 () ]
[ m49751:1065 () ]
[ m49758:1064 () ]
[ m49764:1065 () ]
[ m49790:1064 () ]
[ m49796:1060 () ]
[ m49800:1061 () ]
[ m49812:1065 () ]
[ m51028:1059 () ]
[ m51034:1059 () ]
[ m51040:1059 () ]
[ m51048:1065 () ]
[ m56838:1063 () ]
[ m56843:1063 () ]
[ m56851:1065 () ]
[ m56857:1065 () ]
[ m56878:1065 () ]
[ m56885:1065 () ]
[ m56892:1065 () ]
[ m56898:1064 () ]
[ m32356:1066 () ]
[ m32364:1039 () ]
[ m32372:1064 () ]
[ m32375:1065 () ]
[ m34527:1065 () ]
[ m34530:1065 () ]
[ m34538:1065 () ]
[ m34545:1064 () ]
[ m34663:1065 () ]
[ m34670:1066 () ]
[ m34677:1053 () ]
[ m34692:1053 () ]
[ m45022:1065 () ]
[ m45028:1062 () ]
[ m45033:1063 () ]
[ m45038:1066 () ]
[ m45426:1065 () ]
[ m45434:1065 () ]
[ m45441:1065 () ]
[ m45443:1066 () ]
[ m52116:1053 () ]
[ m52122:1062 () ]
[ m52130:1066 () ]
[ m52136:1065 () ]
[ m2111:1067 (s44040:1240) ]
[ m2123:1061 (s44051:1265) ]
[ m2133:1061 (s44061:1264) ]
[ m2145:1066 (s44072:1265) ]
[ m23823:1067 () ]
[ m23833:1065 () ]
[ m23837:1067 () ]
[ m23842:1062 () ]
[ m25456:1067 () ]
[ m25461:1066 () ]
[ m25467:1062 () ]
[ m25475:1066 () ]
[ m26213:1066 () ]
[ m26220:1067 () ]
[ m26224:1066 () ]
[ m26229:1066 () ]
)when when the collected results for /clause/ are /resultsVar/ /body/ with environment /e/ {
Wish to collect results for $clause with settle 0ms
} with environment {{this builtin-programs/collect.folk} {} {}}
when when the collected results for /clause/ with settle /settle/ are /resultsVar/ /body/ with enviro ()when when the collected results for /clause/ with settle /settle/ are /resultsVar/ /body/ with environment /e/ {
Wish to collect results for $clause with settle $settle
} with environment {{this builtin-programs/collect.folk} {} {}}
when when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ {When {$p1} ()when when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ {When {$p1} has region /r1/ & {$p2} has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}} with environment {{this builtin-programs/regions.folk} {} {}}
when when the /fileType/ save directory is /anything/ /body/ with environment /e/ {
set serdeDire (
[ m827:0 (s1273:0) ]
[ m831:0 (s1273:0) ]
[ m838:0 (s1292:0) ]
[ m840:0 (s1273:0) ]
[ m916:0 (s1292:0) ]
[ m938:0 (s1273:0) ]
[ m1043:0 (s1273:0) ]
)when when the /fileType/ save directory is /anything/ /body/ with environment /e/ {
set serdeDirectory "$dataDirectory/$fileType"
# make sure directory exists
file mkdir $serdeDirectory
Claim the $fileType save directory is $serdeDirectory
} with environment {{this builtin-programs/saving/saving.folk} {} {dataDirectory /home/folk/folk-data}}
when when the TrOCR text recognizer is /any/ /any/ with environment /any/ {
Wish -keep 500ms to l ()when when the TrOCR text recognizer is /any/ /any/ with environment /any/ {
Wish -keep 500ms to load the TrOCR text recognizer
} with environment {{this builtin-programs/recognition/trocr.folk} {} {}}
when when the SAM2 segmenter is /any/ /any/ with environment /any/ {
Wish -keep 500ms to load the ()when when the SAM2 segmenter is /any/ /any/ with environment /any/ {
Wish -keep 500ms to load the SAM2 segmenter
} with environment {{this builtin-programs/recognition/sam2.folk} {} {}}
when when the CRAFT text detector is /any/ /any/ with environment /any/ {
Wish -keep 500ms to loa ()when when the CRAFT text detector is /any/ /any/ with environment /any/ {
Wish -keep 500ms to load the CRAFT text detector
} with environment {{this builtin-programs/recognition/craft.folk} {} {}}
when when /rect/ points /direction/ with length /l/ at /someone/ /lambda/ with environment /e/ {
if ()when when /rect/ points /direction/ with length /l/ at /someone/ /lambda/ with environment /e/ {
if {[string match "/*" $rect]} { return }
Wish $rect points $direction with length $l
} with environment {{this builtin-programs/points-at.folk} {} {}}
when when /rect/ points /direction/ at /someone/ /lambda/ with environment /e/ {
if {[string match ()when when /rect/ points /direction/ at /someone/ /lambda/ with environment /e/ {
if {[string match "/*" $rect]} { return }
Wish $rect points $direction with length 1
} with environment {{this builtin-programs/points-at.folk} {} {}}
when when /p/ has neighbor /n/ /lambda/ with environment /e/ {
Wish $p has neighbors
} with environ ()when when /p/ has neighbor /n/ /lambda/ with environment /e/ {
Wish $p has neighbors
} with environment {{this builtin-programs/intersect.folk} {} {}}
when when /p/ has camera slice /slice/ /lambda/ with environment /e/ {
Wish -nonatomically $p has (
[ m3379:1021 (s32231:1215) ]
[ m61905:1054 () ]
[ m47750:1059 (s64517:1262) ]
[ m26067:1066 () ]
[ m26129:1067 () ]
[ m26136:1066 () ]
[ m26158:1067 () ]
[ m26178:1066 () ]
[ m26234:1066 () ]
[ m26513:1067 () ]
[ m26570:1067 () ]
)when when /p/ has camera slice /slice/ /lambda/ with environment /e/ {
Wish -nonatomically $p has camera slice
} with environment {{this builtin-programs/camera/slice.folk} {} {}}
when /someone/ wishes to collect results for /pattern/ with settle /settle/ {
if {[string match { (
[ m210:0 (s319:0) ]
[ m212:0 (s335:0) ]
[ m211:0 (s317:0) ]
[ m213:0 (s325:0) ]
[ m218:0 (s323:0) ]
[ m215:0 (s318:0) ]
[ m217:0 (s322:0) ]
[ m209:0 (s320:0) ]
[ m216:0 (s321:0) ]
[ m214:0 (s336:0) ]
[ m219:0 (s324:0) ]
[ m236:0 (s364:0) ]
[ m238:0 (s369:0) ]
[ m239:0 (s368:0) ]
[ m240:0 (s370:0) ]
[ m241:0 (s374:0) ]
[ m243:0 (s379:0) ]
[ m249:0 (s385:0) ]
[ m253:0 (s391:0) ]
[ m256:0 (s394:0) ]
[ m261:0 (s398:0) ]
[ m263:0 (s400:0) ]
[ m266:0 (s404:0) ]
[ m277:0 (s420:0) ]
[ m279:0 (s429:0) ]
[ m281:0 (s434:0) ]
[ m282:0 (s435:0) ]
[ m283:0 (s436:0) ]
[ m284:0 (s439:0) ]
[ m287:0 (s442:0) ]
[ m291:0 (s449:0) ]
[ m294:0 (s454:0) ]
[ m295:0 (s452:0) ]
[ m300:0 (s463:0) ]
[ m302:0 (s470:0) ]
[ m303:0 (s478:0) ]
[ m307:0 (s481:0) ]
[ m310:0 (s484:0) ]
[ m312:0 (s485:0) ]
[ m320:0 (s499:0) ]
[ m321:0 (s502:0) ]
[ m325:0 (s505:0) ]
[ m330:0 (s513:0) ]
[ m334:0 (s520:0) ]
[ m335:0 (s522:0) ]
[ m337:0 (s526:0) ]
[ m338:0 (s527:0) ]
[ m343:0 (s531:0) ]
[ m350:0 (s549:0) ]
[ m353:0 (s554:0) ]
[ m355:0 (s552:0) ]
[ m357:0 (s555:0) ]
[ m361:0 (s565:0) ]
[ m368:0 (s576:0) ]
[ m369:0 (s579:0) ]
[ m372:0 (s583:0) ]
[ m374:0 (s586:0) ]
[ m381:0 (s599:0) ]
[ m382:0 (s602:0) ]
[ m384:0 (s607:0) ]
[ m386:0 (s609:0) ]
[ m394:0 (s617:0) ]
[ m395:0 (s618:0) ]
[ m400:0 (s625:0) ]
[ m403:0 (s636:0) ]
[ m405:0 (s641:0) ]
[ m406:0 (s643:0) ]
[ m410:0 (s653:0) ]
[ m414:0 (s660:0) ]
[ m418:0 (s665:0) ]
[ m421:0 (s670:0) ]
[ m424:0 (s675:0) ]
[ m428:0 (s684:0) ]
[ m431:0 (s687:0) ]
[ m432:0 (s688:0) ]
[ m437:0 (s697:0) ]
[ m441:0 (s708:0) ]
[ m442:0 (s707:0) ]
[ m443:0 (s712:0) ]
[ m447:0 (s716:0) ]
[ m448:0 (s719:0) ]
[ m454:0 (s727:0) ]
[ m456:0 (s731:0) ]
[ m459:0 (s735:0) ]
[ m463:0 (s742:0) ]
[ m467:0 (s745:0) ]
[ m472:0 (s753:0) ]
[ m473:0 (s751:0) ]
[ m475:0 (s756:0) ]
[ m480:0 (s768:0) ]
[ m481:0 (s767:0) ]
[ m483:0 (s771:0) ]
[ m491:0 (s781:0) ]
[ m495:0 (s789:0) ]
[ m498:0 (s793:0) ]
[ m501:0 (s800:0) ]
[ m503:0 (s798:0) ]
[ m507:0 (s806:0) ]
[ m509:0 (s813:0) ]
[ m514:0 (s820:0) ]
[ m515:0 (s823:0) ]
[ m516:0 (s819:0) ]
[ m523:0 (s830:0) ]
[ m529:0 (s835:0) ]
[ m531:0 (s842:0) ]
[ m533:0 (s844:0) ]
[ m535:0 (s845:0) ]
[ m543:0 (s856:0) ]
[ m544:0 (s859:0) ]
[ m548:0 (s864:0) ]
[ m550:0 (s866:0) ]
[ m556:0 (s874:0) ]
[ m558:0 (s880:0) ]
[ m559:0 (s878:0) ]
[ m566:0 (s887:0) ]
[ m569:0 (s892:0) ]
[ m573:0 (s897:0) ]
[ m579:0 (s903:0) ]
[ m581:0 (s906:0) ]
[ m584:0 (s914:0) ]
[ m586:0 (s916:0) ]
[ m593:0 (s923:0) ]
[ m596:0 (s928:0) ]
[ m599:0 (s932:0) ]
[ m602:0 (s937:0) ]
[ m607:0 (s943:0) ]
[ m610:0 (s948:0) ]
[ m615:0 (s954:0) ]
[ m618:0 (s959:0) ]
[ m621:0 (s963:0) ]
[ m624:0 (s968:0) ]
[ m627:0 (s972:0) ]
[ m630:0 (s977:0) ]
[ m633:0 (s981:0) ]
[ m636:0 (s986:0) ]
[ m641:0 (s992:0) ]
[ m644:0 (s997:0) ]
[ m649:0 (s1003:0) ]
[ m652:0 (s1008:0) ]
[ m657:0 (s1014:0) ]
[ m660:0 (s1019:0) ]
[ m663:0 (s1024:0) ]
[ m666:0 (s1029:0) ]
[ m670:0 (s1037:0) ]
[ m680:0 (s1047:0) ]
[ m682:0 (s1052:0) ]
[ m685:0 (s1057:0) ]
[ m688:0 (s1061:0) ]
[ m691:0 (s1066:0) ]
[ m694:0 (s1070:0) ]
[ m697:0 (s1075:0) ]
[ m700:0 (s1079:0) ]
[ m703:0 (s1084:0) ]
[ m706:0 (s1088:0) ]
[ m709:0 (s1093:0) ]
[ m712:0 (s1096:0) ]
[ m715:0 (s1101:0) ]
[ m718:0 (s1105:0) ]
[ m721:0 (s1110:0) ]
[ m725:0 (s1117:0) ]
[ m728:0 (s1122:0) ]
[ m731:0 (s1126:0) ]
[ m734:0 (s1131:0) ]
[ m738:0 (s1137:0) ]
[ m741:0 (s1142:0) ]
[ m745:0 (s1147:0) ]
[ m748:0 (s1152:0) ]
[ m751:0 (s1156:0) ]
[ m754:0 (s1161:0) ]
[ m759:0 (s1167:0) ]
[ m762:0 (s1172:0) ]
[ m765:0 (s1176:0) ]
[ m768:0 (s1181:0) ]
[ m772:0 (s1187:0) ]
[ m775:0 (s1192:0) ]
[ m778:0 (s1196:0) ]
[ m781:0 (s1201:0) ]
[ m784:0 (s1206:0) ]
[ m787:0 (s1211:0) ]
[ m790:0 (s1215:0) ]
[ m793:0 (s1220:0) ]
[ m796:0 (s1224:0) ]
[ m799:0 (s1229:0) ]
[ m803:0 (s1234:0) ]
[ m806:0 (s1239:0) ]
[ m809:0 (s1244:0) ]
[ m812:0 (s1249:0) ]
[ m815:0 (s1254:0) ]
[ m818:0 (s1259:0) ]
[ m821:0 (s1263:0) ]
[ m824:0 (s1268:0) ]
[ m832:0 (s1283:0) ]
[ m835:0 (s1288:0) ]
[ m842:0 (s1296:0) ]
[ m845:0 (s1301:0) ]
[ m850:0 (s1307:0) ]
[ m853:0 (s1312:0) ]
[ m856:0 (s1318:0) ]
[ m859:0 (s1323:0) ]
[ m862:0 (s1329:0) ]
[ m865:0 (s1334:0) ]
[ m868:0 (s1339:0) ]
[ m871:0 (s1344:0) ]
[ m874:0 (s1352:0) ]
[ m877:0 (s1357:0) ]
[ m880:0 (s1362:0) ]
[ m883:0 (s1367:0) ]
[ m886:0 (s1372:0) ]
[ m889:0 (s1377:0) ]
[ m892:0 (s1382:0) ]
[ m895:0 (s1387:0) ]
[ m1026:0 (s1802:0) ]
[ m1029:0 (s1806:0) ]
[ m1064:0 (s1852:0) ]
[ m1098:0 (s1893:0) ]
[ m1401:0 (s2265:0) ]
[ m4496:0 (s6299:0) ]
[ m23594:0 (s31255:0) ]
[ m23660:0 (s31349:0) ]
[ m23670:0 (s31367:0) ]
[ m5185:43 (s12993:51) ]
[ m28092:625 (s55980:745) ]
[ m47951:637 (s15557:766) ]
[ m48153:638 (s15793:766) ]
[ m57097:694 (s38539:826) ]
[ m33925:727 (s14331:857) ]
[ m33931:727 (s14338:856) ]
[ m33937:727 (s14347:851) ]
[ m25657:915 (s2788:1088) ]
[ m25757:915 (s2899:1083) ]
[ m6394:989 (s52873:1174) ]
[ m6511:990 (s53025:1175) ]
[ m6573:964 (s53117:1170) ]
[ m6582:986 (s53125:1175) ]
[ m6721:979 (s53278:1175) ]
[ m6729:979 (s53290:1175) ]
[ m6752:990 (s53316:1175) ]
[ m3059:1024 (s31839:1214) ]
[ m3091:1024 (s31883:1215) ]
[ m3372:1022 (s32223:1215) ]
[ m3375:1022 (s32228:1214) ]
[ m44360:1038 (s51510:1233) ]
[ m44366:1038 (s51518:1233) ]
[ m44373:1035 (s51528:1233) ]
[ m44378:1034 (s51537:1233) ]
[ m44639:1032 (s51835:1233) ]
[ m44684:1039 (s51885:1229) ]
[ m42528:1051 (s60011:1247) ]
[ m16189:1052 (s40286:1249) ]
[ m16194:1053 (s40291:1249) ]
[ m16199:1048 (s40295:1248) ]
[ m16203:1053 (s40298:1249) ]
[ m16436:1044 (s40611:1194) ]
[ m16465:1051 (s40618:1195) ]
[ m16466:1048 (s40619:1248) ]
[ m16475:1050 (s40627:1194) ]
[ m61803:1036 (s49325:1252) ]
[ m61816:1044 (s49342:1241) ]
[ m61825:1042 (s49351:1252) ]
[ m61858:1037 (s49386:1248) ]
[ m61883:1047 (s49421:1249) ]
[ m61891:975 (s49427:1236) ]
[ m61897:1055 (s49435:1252) ]
[ m61907:1048 (s49444:1252) ]
[ m61932:1052 (s49464:1250) ]
[ m62005:1055 (s49550:1245) ]
[ m24806:1055 () ]
[ m65100:1057 () ]
[ m65102:1056 () ]
[ m65133:1057 () ]
[ m17867:1058 (s28222:1254) ]
[ m17875:1058 (s28230:1240) ]
[ m17882:1053 (s28244:1239) ]
[ m17884:1057 (s28249:1245) ]
[ m23204:1061 (s14509:1257) ]
[ m23213:1061 (s14515:1260) ]
[ m23222:1061 (s14526:1256) ]
[ m23228:1059 (s14530:1259) ]
[ m23348:1059 (s14675:1259) ]
[ m23385:1039 (s14729:1259) ]
[ m23390:1062 (s14735:1259) ]
[ m23400:1062 (s14745:1220) ]
[ m23406:1062 (s14752:1222) ]
[ m23411:1062 (s14758:1257) ]
[ m23418:1062 (s14764:1260) ]
[ m23430:1062 (s14776:1223) ]
[ m23485:1060 (s14838:1260) ]
[ m23751:1058 (s15104:1259) ]
[ m23759:1061 (s15110:1259) ]
[ m23764:1060 (s15115:1256) ]
[ m23768:1057 (s15120:1256) ]
[ m24272:1061 () ]
[ m24276:1050 () ]
[ m24283:1057 () ]
[ m24290:1061 () ]
[ m24310:1062 () ]
[ m24315:1053 () ]
[ m24321:1042 () ]
[ m24326:1052 () ]
[ m25399:1062 () ]
[ m25406:1062 () ]
[ m25419:1062 () ]
[ m25430:1062 () ]
[ m11520:1063 () ]
[ m11530:1060 () ]
[ m11539:1060 () ]
[ m11545:1060 () ]
[ m53883:1063 () ]
[ m53898:1063 () ]
[ m53911:1057 () ]
[ m53927:1058 () ]
[ m57108:1063 () ]
[ m57110:767 () ]
[ m57114:768 () ]
[ m57117:1045 () ]
[ m57121:768 () ]
[ m57124:1060 () ]
[ m57126:1063 () ]
[ m57130:768 () ]
[ m12165:1064 () ]
[ m12171:1061 () ]
[ m12175:1063 () ]
[ m12179:1063 () ]
[ m12475:1063 () ]
[ m12482:1064 () ]
[ m12490:1061 () ]
[ m12497:1062 () ]
[ m20133:1063 () ]
[ m20140:1062 () ]
[ m20145:1061 () ]
[ m20154:1061 () ]
[ m25177:1063 () ]
[ m25183:1064 () ]
[ m25189:1063 () ]
[ m25193:1064 () ]
[ m25309:1062 () ]
[ m25315:1063 () ]
[ m25321:1064 () ]
[ m25333:1062 () ]
[ m25481:1059 () ]
[ m25487:1064 () ]
[ m25492:1063 () ]
[ m25494:1064 () ]
[ m25498:1063 () ]
[ m25500:1064 () ]
[ m25506:1063 () ]
[ m25511:1064 () ]
[ m29756:1063 () ]
[ m29760:1052 () ]
[ m29764:1056 () ]
[ m29769:1059 () ]
[ m34715:1064 () ]
[ m34726:1064 () ]
[ m34733:1064 () ]
[ m34742:1064 () ]
[ m40449:1063 () ]
[ m40455:1064 () ]
[ m40459:1064 () ]
[ m40465:1063 () ]
[ m47703:1064 (s64452:1262) ]
[ m47713:1064 (s64467:990) ]
[ m47774:1064 (s64538:1262) ]
[ m47784:1064 (s64549:1258) ]
[ m47878:1064 () ]
[ m47885:1064 () ]
[ m47892:1064 () ]
[ m47902:1064 () ]
[ m53653:1064 () ]
[ m53658:1064 () ]
[ m53670:1064 () ]
[ m53677:1064 () ]
[ m60524:1052 (s15413:1261) ]
[ m60528:1060 (s15419:1263) ]
[ m60533:1058 (s15423:1258) ]
[ m60538:1064 (s15429:1260) ]
[ m61132:1064 () ]
[ m61138:1064 () ]
[ m61143:1064 () ]
[ m61149:1058 () ]
[ m61429:1064 () ]
[ m61434:1064 () ]
[ m61439:1064 () ]
[ m61447:1063 () ]
[ m61465:1064 () ]
[ m61472:1055 () ]
[ m61479:1064 () ]
[ m61487:1061 () ]
[ m10496:1063 () ]
[ m10505:1065 () ]
[ m10513:1064 () ]
[ m10521:1064 () ]
[ m10733:1059 () ]
[ m10738:1063 () ]
[ m10741:1063 () ]
[ m10746:1064 () ]
[ m10775:1065 () ]
[ m10783:1065 () ]
[ m10793:1060 () ]
[ m10799:1054 () ]
[ m11032:1065 () ]
[ m11035:1065 () ]
[ m11039:1065 () ]
[ m11044:1065 () ]
[ m13841:1065 () ]
[ m13845:1065 () ]
[ m13850:1065 () ]
[ m13855:1065 () ]
[ m29759:1057 () ]
[ m29765:1064 () ]
[ m29771:1055 () ]
[ m29773:1064 () ]
[ m29779:1063 () ]
[ m29782:1059 () ]
[ m29790:1060 () ]
[ m29795:1060 () ]
[ m30075:1065 () ]
[ m30083:1064 () ]
[ m30084:1065 () ]
[ m30091:1064 () ]
[ m30107:1064 () ]
[ m30114:1063 () ]
[ m30122:1063 () ]
[ m30127:1063 () ]
[ m40581:1065 () ]
[ m40582:1062 () ]
[ m40591:1057 () ]
[ m40598:1065 () ]
[ m43959:1065 () ]
[ m43963:1065 () ]
[ m43972:1057 () ]
[ m43979:1065 () ]
[ m48882:1063 () ]
[ m48893:1064 () ]
[ m48897:1063 () ]
[ m48904:1065 () ]
[ m49746:1063 () ]
[ m49753:1061 () ]
[ m49759:1062 () ]
[ m49766:1061 () ]
[ m49791:1065 () ]
[ m49797:1065 () ]
[ m49801:1065 () ]
[ m49813:1064 () ]
[ m51030:1064 () ]
[ m51035:1058 () ]
[ m51041:1059 () ]
[ m51049:1059 () ]
[ m56839:1065 () ]
[ m56845:1065 () ]
[ m56853:1059 () ]
[ m56858:1058 () ]
[ m56879:1065 () ]
[ m56887:1065 () ]
[ m56894:1064 () ]
[ m56900:1064 () ]
[ m32358:1066 () ]
[ m32366:1035 () ]
[ m32373:1066 () ]
[ m32376:1065 () ]
[ m34528:1066 () ]
[ m34531:1065 () ]
[ m34540:1064 () ]
[ m34547:1065 () ]
[ m34665:1066 () ]
[ m34671:1053 () ]
[ m34678:1053 () ]
[ m34694:1066 () ]
[ m45023:1061 () ]
[ m45030:1066 () ]
[ m45034:1064 () ]
[ m45039:1063 () ]
[ m45427:1065 () ]
[ m45436:1065 () ]
[ m45442:1063 () ]
[ m45444:1064 () ]
[ m52118:1061 () ]
[ m52124:1065 () ]
[ m52132:1065 () ]
[ m52138:1065 () ]
[ m2114:1067 (s44041:1265) ]
[ m2126:1067 (s44052:1239) ]
[ m2136:1062 (s44063:1264) ]
[ m2147:1065 (s44077:1255) ]
[ m23826:1067 () ]
[ m23834:1060 () ]
[ m23838:1060 () ]
[ m23844:1064 () ]
[ m25457:1065 () ]
[ m25462:1064 () ]
[ m25468:1065 () ]
[ m25478:1065 () ]
[ m26215:1065 () ]
[ m26221:1067 () ]
[ m26225:1066 () ]
[ m26230:1066 () ]
)when /someone/ wishes to collect results for /pattern/ with settle /settle/ {
if {[string match {*ms} $settle]} {
set settleMs [string range $settle 0 end-2]
set settleNs [* $settleMs 1000000]
}
When {*}$pattern {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
}
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>}}
when /someone/ wishes to draw a shape with /...options/ \n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exist ()when /someone/ wishes to draw a shape with /...options/ \n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes to draw a triangle with /...options/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ ()when /someone/ wishes to draw a triangle with /...options/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /someone/ wishes to draw a quad onto /p/ with /...options/ {When {$p} has canvas /id/ with /...w (
[ m6776:1047 (s38746:1262) ]
[ m26085:1067 () ]
[ m26359:1067 () ]
[ m26368:1066 () ]
[ m26416:1067 () ]
[ m26460:1065 () ]
[ m26505:1065 () ]
[ m26547:1067 () ]
[ m26581:1067 () ]
[ m26634:1067 () ]
[ m26648:1067 () ]
[ m26685:1067 (s8267:1266) ]
[ m26693:1067 (s8277:1266) ]
[ m26727:1067 (s8309:1266) ]
[ m26772:1067 (s8362:1265) ]
[ m26781:1065 (s8371:1266) ]
)when /someone/ wishes to draw a quad onto /p/ with /...options/ {When {$p} has canvas /id/ with /...wiOptions/ & {$p} has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /someone/ wishes to draw a polygon with /...options/ \n\ \ \ \ set\ points\ \[dict\ get\ \$optio ()when /someone/ wishes to draw a polygon with /...options/ \n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /someone/ wishes to draw a curve with /...options/ \n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ ()when /someone/ wishes to draw a curve with /...options/ \n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/display/curve.folk} {} {}}
when /someone/ wishes to draw a dashed line onto monitor with /...options/ \n\n\ \ \ \ set\ points\ \ ()when /someone/ wishes to draw a dashed line onto monitor with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 11 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 11 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 82 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 82 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 62 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 62 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 63 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 63 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 54 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 54 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 54-display with /...options/ \n\n\ \ \ \ set\ points ()when /someone/ wishes to draw a dashed line onto 54-display with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {} {surfaceToClip {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a dashed line onto 83 with /...options/ \n\n\ \ \ \ set\ points\ \[dict ()when /someone/ wishes to draw a dashed line onto 83 with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto monitor with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ g (
[ m26123:1065 () ]
[ m26147:1065 () ]
[ m26157:1067 () ]
[ m26175:1067 () ]
[ m26198:1067 () ]
[ m26258:1066 () ]
[ m26559:1067 () ]
)when /someone/ wishes to draw a line onto monitor with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 11 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef ()when /someone/ wishes to draw a line onto 11 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 82 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef (
[ m42663:1047 () ]
[ m1790:1056 () ]
[ m43512:1052 () ]
[ m24905:1054 () ]
[ m65128:1057 () ]
[ m47738:1064 (s64507:1262) ]
)when /someone/ wishes to draw a line onto 82 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 62 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef ()when /someone/ wishes to draw a line onto 62 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 63 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef ()when /someone/ wishes to draw a line onto 63 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 54 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef (
[ m23372:1062 (s14705:1259) ]
)when /someone/ wishes to draw a line onto 54 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 54-display with /...options/ \n\n\ \ \ \ set\ layer\ \[dict (
[ m4596:1067 () ]
[ m14244:1066 () ]
[ m23128:1067 () ]
[ m23481:1066 () ]
[ m23978:1062 () ]
[ m26481:1067 () ]
[ m26868:1065 (s8486:1266) ]
)when /someone/ wishes to draw a line onto 54-display with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {} {surfaceToClip {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a line onto 83 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef (
[ m47755:1060 (s64524:1258) ]
)when /someone/ wishes to draw a line onto 83 with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto monitor with /...options/ \n\n\ \ \ \ set\ center\ \[dict ()when /someone/ wishes to draw a circle onto monitor with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 11 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 11 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 82 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 82 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 62 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 62 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 63 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 63 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 54 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 54 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 54-display with /...options/ \n\n\ \ \ \ set\ center\ \[d ()when /someone/ wishes to draw a circle onto 54-display with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {} {surfaceToClip {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}} {}}
when /someone/ wishes to draw a circle onto 83 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ get ()when /someone/ wishes to draw a circle onto 83 with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an arc with /...options/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ ()when /someone/ wishes to draw an arc with /...options/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n with environment {{this builtin-programs/display/arc.folk} {} {}}
when /someone/ wishes to draw an image onto /p/ with /...options/ {When {$p} has canvas /id/ with /.. (
[ m24432:938 (s5652:1265) ]
[ m25400:1067 () ]
[ m25710:1065 () ]
[ m25792:1067 () ]
[ m25839:942 () ]
[ m25892:943 () ]
[ m25916:1067 () ]
[ m26038:1067 () ]
[ m26111:1067 () ]
[ m26228:1067 () ]
[ m26533:1067 (s8093:1265) ]
[ m26550:1067 () ]
[ m26743:1067 (s8330:1266) ]
)when /someone/ wishes to draw an image onto /p/ with /...options/ {When {$p} has canvas /id/ with /...wiOptions/ & {$p} has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when /someone/ wishes to draw an AprilTag onto monitor with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ ()when /someone/ wishes to draw an AprilTag onto monitor with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p monitor writableTexture {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {} {surfaceToClip {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 11 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 11 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 11 writableTexture {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 82 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 82 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 82 writableTexture {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 62 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 62 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 62 writableTexture {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 63 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 63 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 63 writableTexture {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 54 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 54 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 54 writableTexture {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {} {surfaceToClip {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 54-display with /...options/ \n\n\ \ \ \ set\ id\ \[di ()when /someone/ wishes to draw an AprilTag onto 54-display with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 54-display writableTexture {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {} {surfaceToClip {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}} {}}
when /someone/ wishes to draw an AprilTag onto 83 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ ()when /someone/ wishes to draw an AprilTag onto 83 with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 83 writableTexture {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when /someone/ wishes to draw text onto /p/ with /...options/ \n\ \ \ \ if\ \{\[dict\ exists\ \$optio (
[ m51774:1064 (s16230:1264) ]
[ m26589:1067 () ]
[ m26633:1066 () ]
[ m26662:1067 () ]
[ m26748:1067 () ]
[ m26760:1067 () ]
[ m26800:1067 (s8403:1266) ]
[ m26865:1067 () ]
[ m26884:1066 () ]
[ m26899:1067 (s8518:1266) ]
[ m26905:1066 (s8523:1266) ]
)when /someone/ wishes to draw text onto /p/ with /...options/ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /someone/ wishes to draw calibration model /model/ using model-to-display homography /H_modelToD ()when /someone/ wishes to draw calibration model /model/ using model-to-display homography /H_modelToDisplay/ with message /calibrationMessage/ \n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n with environment {{this builtin-programs/calibrate/draw-model.folk} {} {} {display monitor displayWidth 4096 displayHeight 2160} {} {matLib <C:cfile5JsRBY>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {}}
when /someone/ wishes to load the TrOCR text recognizer {When the image uvx argtype definer is /defin ()when /someone/ wishes to load the TrOCR text recognizer {When the image uvx argtype definer is /defineImageArgtype/ {
fn defineImageArgtype
set py [Uvx --with transformers --with pillow --with torch --with protobuf]
defineImageArgtype $py
$py exec {
from transformers import TrOCRProcessor, VisionEncoderDecoderModel
import os
import sys
import torch
import time
# Determine device (prefer CUDA > MPS > CPU)
if torch.cuda.is_available():
device = "cuda"
elif torch.backends.mps.is_available():
device = "mps"
else:
device = "cpu"
# Load TrOCR model
TROCR_PATH = os.path.expanduser("~/folk-data/trocr")
try:
processor = TrOCRProcessor.from_pretrained(TROCR_PATH)
model = VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)
print("trocr: Loaded TrOCR model from disk.", file=sys.stderr, flush=True)
except Exception:
print("trocr: Model not saved; loading from Internet.", file=sys.stderr, flush=True)
processor = TrOCRProcessor.from_pretrained("microsoft/trocr-base-handwritten")
processor.save_pretrained(TROCR_PATH)
model = VisionEncoderDecoderModel.from_pretrained("microsoft/trocr-base-handwritten")
model.save_pretrained(TROCR_PATH)
print("trocr: Loaded TrOCR model from Internet.", file=sys.stderr, flush=True)
model.to(device)
print(f"trocr: Using device: {device}", file=sys.stderr, flush=True)
}
$py def ocrImage {Image image} {
start_time = time.time()
# Run TrOCR on the entire image
with torch.no_grad():
pixel_values = processor(image, return_tensors="pt").pixel_values.to(device)
generated_ids = model.generate(pixel_values)
text = processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
elapsed = time.time() - start_time
print(f"trocr: Result: {text} ({elapsed:.3f}s)", file=sys.stderr, flush=True)
return text
}
fn TrOCR {im} { return [$py ocrImage $im] }
Claim the TrOCR text recognizer is [fn TrOCR]
}} with environment {{this builtin-programs/recognition/trocr.folk} {} {}}
when /someone/ wishes to load the SAM2 segmenter {When the image uvx argtype definer is /defineImageA ()when /someone/ wishes to load the SAM2 segmenter {When the image uvx argtype definer is /defineImageArgtype/ \n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n} with environment {{this builtin-programs/recognition/sam2.folk} {} {}}
when /someone/ wishes to load the CRAFT text detector {When the image uvx argtype definer is /defineI ()when /someone/ wishes to load the CRAFT text detector {When the image uvx argtype definer is /defineImageArgtype/ {
fn defineImageArgtype
set py [Uvx --with pillow --with "git+https://github.com/osnr/craft-text-detector.git"]
defineImageArgtype $py
$py exec {
import torch
import numpy as np
from craft_text_detector import Craft
import time
if torch.cuda.is_available():
device = "cuda"
elif torch.backends.mps.is_available():
device = "mps"
else:
device = "cpu"
craft = Craft(output_dir=None, crop_type="box",
link_threshold=0.1, device=device)
}
$py def detectTextBoxes {Image image} {
image_np = np.array(image)
start_craft = time.time()
result = craft.detect_text(image_np)
boxes = result["boxes"]
craft_time = time.time() - start_craft
print(f"craft: Detected {len(boxes)} text boxes ({craft_time:.3f}s)",
file=sys.stderr, flush=True)
return boxes.tolist() if hasattr(boxes, 'tolist') else boxes
}
fn CRAFT {im} { return [$py detectTextBoxes $im] }
Claim the CRAFT text detector is [fn CRAFT]
}} with environment {{this builtin-programs/recognition/craft.folk} {} {}}
when /someone/ wishes to deserialize namespace hold with directory /directory/ {
set holdFiles [g (
[ m920:0 (s1598:0) ]
)when /someone/ wishes to deserialize namespace hold with directory /directory/ {
set holdFiles [glob -nocomplain $directory/*]
foreach holdFile $holdFiles {
set fd [open $holdFile r]
set holds [read $fd]
close $fd
# the hold file's first line is its canonical name (since
# having / in a filename would mess a lot of stuff up),
# while the rest of the file is a dict of holds
set canonicalName [lindex $holds 0]
set holdDict [lrange $holds 1 end]
dict for {key clause} $holdDict {
Hold! -on $canonicalName -key $key -- {*}$clause
}
$savedHoldsLib loadHolds $canonicalName $holdDict
}
Claim the saved holds are loaded
} with environment {{this builtin-programs/saving/save-holds.folk} {} {savedHoldsLib <C:cfilecAUX4H> cc ::<reference.<C______>.00000000000000000006>}}
when /someone/ wishes to detect laser blobs {When camera /any/ has gray frame /grayFrame/ at timestam ()when /someone/ wishes to detect laser blobs {When camera /any/ has gray frame /grayFrame/ at timestamp /timestamp/ {
set blobTime [time {
set threshold 250
set blobs [$blobdetectLib detect $grayFrame $threshold]
}]
Hold! {
Claim the blob detection time is $blobTime
foreach blob $blobs {
Claim laser blob [dict get $blob id] has center [dict get $blob center] size [dict get $blob size]
}
}
}} with environment {{this builtin-programs/laser.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} blobdetectLib <C:cfile2I7SSq> cc ::<reference.<C______>.00000000000000000002>}}
when /someone/ wishes to calibrate camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index ()when /someone/ wishes to calibrate camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {display monitor displayWidth 4096 displayHeight 2160} {} {makeAprilTagDetector {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}}}}}} {} {jpegLib <C:cfileZXB3iE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {}}
when /someone/ wishes to play audio /sound/ {
# Check if the sound file exists in the user-progr ()when /someone/ wishes to play audio /sound/ {
# Check if the sound file exists in the user-programs/$hostname/sounds directory
# or in the working directory's assets/sounds subdirectory. Otherwise, assume
# it's an absolute path.
proc resolveSoundPath {filename} {
set scriptDir [file dirname [info script]]
set projectRoot [pwd]
set hostname [info hostname]
set path "$projectRoot/user-programs/$hostname/audio/$filename"
if {[file exists $path]} { return $path }
set path "$projectRoot/audio/$filename"
if {[file exists $path]} { return $path }
# treat as an absolute path
return $filename
}
set path [resolveSoundPath $sound]
if {![file exists $path]} {
puts stderr "audio: File not found '$path'"
return
}
set handle [$audioLib playSound $path]
if {$handle == 0} {
puts stderr "audio: Failed to play '$path'"
return
}
On unmatch {
puts "audio: stopping audio '$path'"
$audioLib audioStop $handle
}
} with environment {{this builtin-programs/audio.folk} {} {success 1 audioLib <C:cfileaDB4QL> cc ::<reference.<C______>.00000000000000000002>} {audioLib <C:cfileaDB4QL>} {}}
when /someone/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...replacedO ()when /someone/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/keyboard-shortcuts.folk programCode {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard-shortcuts.folk, match m10029:6: Failed to restart folk.service: Interactive authentication required.
#
# TODO: Figure out how to do this with less powerful permissions than `sudo`. (@cwervo)
# Keyboard shortcuts
# ---
# Alt + Esc: Restart Folk
# Alt + F1: Stop Folk completely (note: need to ssh to restart Folk)
# Alt-Esc on most keyboards
Subscribe: keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
}
# Console_1 corresponds to Alt-F1 on most keyboards
Subscribe: keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/mask-tags.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/mask-tags.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/mask-tags.folk programCode When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ width\ /projWidth/\ height\ /projHeight/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ intrinsics\ /projectorIntrinsics/\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/terminal.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/terminal.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/terminal.folk programCode #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/errors.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/errors.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/errors.folk programCode {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
}
When /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/demos.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/demos.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/demos.folk programCode {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
Claim 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
Claim 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
Claim 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
Claim 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
Claim 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
Claim 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
Claim 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
Claim 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/group.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/group.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/group.folk programCode return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contains\ /...programs/\ \{\n\ \ \ \ Wish\ tag\ \$group\ is\ stabilized\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ claim\ 'tag'\ specifically\ so\ it\ doesn't\ run\ twice\n\ \ \ \ \ \ \ \ Claim\ tag\ \$program\ has\ a\ program\n\ \ \ \ \}\n\}\n\n#\ figure\ out\ the\ text\ to\ display\ below\nWhen\ group\ /group/\ contains\ /...programs/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ /program/\ is\ titled\ /title/\]\ are\ /results/\ \{\n\ \ \ \ set\ programTitles\ \[dict\ create\]\n\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ programId\ \[dict\ get\ \$result\ program\]\n\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$programs\ \$programId\]\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ programTitles\ \$programId\ \[dict\ get\ \$result\ title\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ programTitleText\ \"\"\n\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ set\ title\ \[dict_getdef\ \$programTitles\ \$program\ \"(no\ title)\"\]\n\ \ \ \ \ \ \ \ append\ programTitleText\ \\n\ \$program\ \":\ \"\ \$title\n\ \ \ \ \}\n\n\ \ \ \ Claim\ group\ \$group\ has\ program\ titles\ \$programTitleText\n\}\n\n#\ display\ said\ text\nWhen\ group\ /group/\ has\ program\ titles\ /programTitles/\ &\\\n\ \ \ \ \ /group/\ has\ region\ /r/\ \{\n\ \ \ \ set\ radians\ \[region\ angle\ \$r\]\n\ \ \ \ set\ pos\ \[region\ topleft\ \[region\ move\ \$r\ down\ 40px\ right\ 15px\]\]\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ text\ \$programTitles\ scale\ 0.7\ radians\ \$radians\ anchor\ topleft\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/laser.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/laser.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/laser.folk programCode When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/music.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/music.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/music.folk programCode {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set musicDir $::env(HOME)/music
exec mkdir -p $musicDir
# https://raw.githubusercontent.com/tidalcycles/Tidal/main/BootTidal.hs
set bootTidal {
:set -XOverloadedStrings
:set prompt ""
import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)
hSetEncoding stdout utf8
tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})
:{
let only = (hush >>)
p = streamReplace tidal
hush = streamHush tidal
panic = do hush
once $ sound "superpanic"
list = streamList tidal
mute = streamMute tidal
unmute = streamUnmute tidal
unmuteAll = streamUnmuteAll tidal
unsoloAll = streamUnsoloAll tidal
solo = streamSolo tidal
unsolo = streamUnsolo tidal
once = streamOnce tidal
first = streamFirst tidal
asap = once
nudgeAll = streamNudgeAll tidal
all = streamAll tidal
resetCycles = streamResetCycles tidal
setCycle = streamSetCycle tidal
setcps = asap . cps
getcps = streamGetcps tidal
getnow = streamGetnow tidal
xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
jump i = transition tidal True (Sound.Tidal.Transition.jump) i
jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
d13 = p 13
d14 = p 14
d15 = p 15
d16 = p 16
:}
:{
let getState = streamGet tidal
setI = streamSetI tidal
setF = streamSetF tidal
setS = streamSetS tidal
setR = streamSetR tidal
setB = streamSetB tidal
:}
:set prompt "tidal> "
:set prompt-cont ""
default (Pattern String, Integer, Double)
}
set scStartup [open $musicDir/startup.sc w]
# via https://club.tidalcycles.org/t/tidal-synth-doesnt-work/800 -- it
# doesn't work if you just do SuperDirt.start; for some reason
puts $scStartup {(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 2048; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt.stop; // stop any old ones, avoid duplicate dirt (if it is nil, this won't do anything)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
SuperDirt.default = ~dirt; // make this instance available in sclang (optional)
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
// directly below here, in your own copy of this file, you could add further code that you want to call on startup
// this makes sure the server and ~dirt are running
// you can keep this separate and make it easier to switch between setups
// by using "path/to/my/file.scd".load and if necessary commenting out different load statements
// ...
};
s.latency = 0.3; // increase this if you get "late" messages
};
);}
close $scStartup
set uid [exec id -u $::env(USER)]
set ::env(DBUS_SESSION_BUS_ADDRESS) "unix:path=/run/user/$uid/bus"
exec rm -f $musicDir/music.log
fn musicExec {args} {
if {[lindex $args end] eq "&"} {
exec {*}[lreplace $args end end] >>$musicDir/music.log 2>>$musicDir/music.log &
} else {
exec {*}$args >>$musicDir/music.log 2>>$musicDir/music.log
}
}
fn musicFinishSetup {} {
if {$::thisNode eq "folk-hex"} {
exec jackd -d alsa -d hdmi:CARD=NVidia -r 48000 -p 1024 -n 2 &
} elseif {$::thisNode eq "folk-sva"} {
exec jackd -d alsa -d hdmi:CARD=Generic,DEV=1 -r 48000 -p 1024 -n 2 &
}
catch {exec pkill ghci}
catch {exec pkill ghc}
catch {exec pkill sclang}
catch {exec pkill scsynth}
sleep 0.4
set ::env(QT_QPA_PLATFORM) offscreen
musicExec sclang $musicDir/startup.sc &
set fifo $musicDir/tidal-input
exec rm -f $fifo
exec mkfifo $fifo
sleep 0.2
musicExec sh -c "ghci < $fifo" &
set fifoId [open $fifo w]
puts $fifoId $bootTidal; flush $fifoId
# We keep $fifoId open so that ghci doesn't get an EOF.
}
while true {
puts "music: Waiting for D-Bus."
sleep 0.2
if {[file exists /run/user/$uid/bus]} {
puts "music: Found D-Bus."
musicFinishSetup
break
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/programs.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/programs.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/programs.folk programCode When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{\$tag\ >=\ 48600\}\ \{\ return\ \}\n\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ has\ a\ program\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ is\ a\ tag\n\}\n\nWhen\ -noncapturing\ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/points-at.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/points-at.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/points-at.folk programCode When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ \$l\n\}\n\nWhen\ when\ /rect/\ points\ /direction/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ 1\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /rect/\ points\ /direction/\ with\ length\ /l/\ \{\n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/camera/usb.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/camera/usb.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/camera/usb.folk programCode #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2).\n\nif\ \{\$::tcl_platform(os)\ ne\ \"linux\"\}\ \{\ return\ \}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/intersect.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/intersect.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/intersect.folk programCode \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ /r2/\ \{\n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n\}\n\nWhen\ when\ /p/\ has\ neighbor\ /n/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ Wish\ \$p\ has\ neighbors\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/regions.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/regions.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/regions.folk programCode {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1/ has region /r1/ & /p2/ has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}
When /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/terminal-ui.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/terminal-ui.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/terminal-ui.folk programCode {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/apriltags.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/apriltags.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/apriltags.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/sprites.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/sprites.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/sprites.folk programCode ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumbnail\ grid\ with\ 8\ frames\ and\ 4\ columns\n#\ \ \ When\ \$this\ has\ thumbnail\ grid\ /thumbnails/\ \{\n#\ \ \ \ \ Wish\ \$this\ draws\ \$thumbnails\;\ #\ Would\ need\ to\ query\ \$thumnails\ for\ its\ frameCount\ and\ columns\n#\ \ \ \}\n#######\n\n#\ -\ path\ get\ prepended\ with\ ~/folk-images/\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /anyone/\ wishes\ /p/\ draws\ sprite\ /path/\ with\ /...options/\ \{\n\n\ \ set\ frames\ \[dict\ get\ \$options\ frames\]\n\ \ set\ columns\ \[dict\ get\ \$options\ columns\]\n\ \ set\ fps\ \[dict\ getdef\ \$options\ fps\ 60\]\n\n\ \ fn\ loadImage\n\ \ set\ im\ \[loadImage\ \$path\]\n\n\ \ set\ sheetWidth\ \[\$imageLib\ Image_width\ \$im\]\n\ \ set\ sheetHeight\ \[\$imageLib\ Image_height\ \$im\]\n\ \ set\ spriteWidth\ \[/\ \$sheetWidth\ \$columns\]\n\ \ set\ rows\ \[/\ \$frames\ \$columns\]\n\ \ set\ spriteHeight\ \[/\ \$sheetHeight\ \$rows\]\n\n\ \ When\ -atomicallyWithKey\ \[list\ sprite\ \$p\ \$path\]\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ set\ frameNumber\ \[expr\ \{round\ (\$t\ *\ \$fps)\ %\ \$frames\}\]\n\ \ \ \ \ \ set\ x\ \[expr\ \{(\$frameNumber\ %\ \$columns)\ *\ \$spriteWidth\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{(\$frameNumber\ %\ \$rows)\ *\ \$spriteHeight\}\]\n\n\ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$im\ \$x\ \$y\ \$spriteWidth\ \$spriteHeight\]\n\ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$subimage\ with\ \{*\}\$options\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ Wish\ \$this\ draws\ sprite\ \$path\ with\ 8\ frames\ and\ 4\ columns\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/esc-pos.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/esc-pos.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/esc-pos.folk programCode When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\n\ \ \ \ fn\ printProgram\ \{printer\ id\ code\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ writeFolkFile\ \$id\ \$code\n\ \ \ \ \ \ \ \ writeMetaFile\ \$printer\ \$id\n\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ is\ at\ /address/\n\ \ \ \ \ \ \ \ set\ printerSocket\ \[socket\ stream\ \$\{address\}:9100\]\n\n\ \ \ \ \ \ \ \ fconfigure\ \$printerSocket\ -translation\ binary\ -buffering\ none\n\ \ \ \ \ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[init\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[tag\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\])\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 2\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[cut\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$printerSocket\ \[render\ \$template\]\n\ \ \ \ \ \ \ \ close\ \$printerSocket\n\ \ \ \ \}\n\n\ \ \ \ fn\ render\ \{template\}\ \{\n\ \ \ \ \ \ \ \ set\ trimmed\ \[lmap\ line\ \[split\ \$template\ \"\\n\"\]\ \{\ string\ trim\ \$line\ \}\]\n\ \ \ \ \ \ \ \ set\ singleLine\ \[join\ \$trimmed\ \"\"\]\n\ \ \ \ \ \ \ \ return\ \[uplevel\ \[list\ subst\ \$singleLine\]\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeFolkFile\ \{id\ code\}\ \{\n\ \ \ \ \ \ \ \ set\ folkFile\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$folkFile\ \$code\n\ \ \ \ \ \ \ \ close\ \$folkFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeMetaFile\ \{printer\ id\}\ \{\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ has\ tag\ geometry\ /geometry/\n\ \ \ \ \ \ \ \ set\ metaFile\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$metaFile\ \[subst\ \{Claim\ tag\ \\\$this\ has\ geometry\ \{\$geometry\}\}\]\n\ \ \ \ \ \ \ \ close\ \$metaFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ cut\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1dV\\x0\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ feed\ n\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"\\x1b\\x64%c\"\ \$n\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ init\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1b\\x40\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ raw\ number\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"%c\"\ \$number\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ scaledAprilTag\ \{id\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ \ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\ \}\ \{\$i\ <\ \$scale\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \[expr\ \{\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ !=\ 255\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \{*\}\[lrepeat\ \$scale\ \$bit\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$tagBits\n\ \ \ \ \}\n\n\ \ \ \ #\ scale\ must\ be\ divisible\ by\ 4\ so\ width\ will\ be\ divisible\ by\ 8\n\ \ \ \ fn\ tag\ \{id\ \{scale\ 12\}\}\ \{\n\ \ \ \ \ \ \ \ set\ tagBits\ \[scaledAprilTag\ \$id\ \$scale\]\n\n\ \ \ \ \ \ \ \ set\ width\ \[expr\ \{10\ *\ \$scale\}\]\n\ \ \ \ \ \ \ \ set\ xL\ \[expr\ \{\$width\ /\ 8\}\]\ \ \ \;#\ width\ in\ bytes\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yL\ \[expr\ \{\$width\ %\ 256\}\]\ \;#\ height\ in\ lines\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yH\ \[expr\ \{\$width\ /\ 256\}\]\ \;#\ height\ in\ lines\ (high\ byte)\n\n\ \ \ \ \ \ \ \ return\ \"\\x1dv0\\x03\[raw\ \$xL\]\\x00\[raw\ \$yL\]\[raw\ \$yH\]\[binary\ format\ B*\ \[join\ \$tagBits\ \"\"\]\]\"\n\ \ \ \ \}\n\n\ \ \ \ Subscribe:\ print\ program\ /id/\ on\ receipt\ printer\ /printer/\ with\ code\ /code/\ \{\n\ \ \ \ \ \ \ \ printProgram\ \$printer\ \$id\ \$code\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/keyboard.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/keyboard.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/keyboard.folk programCode #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ \ \ set\ properties\ \[exec\ udevadm\ info\ --query=property\ --name=\$device\]\n\ \ \ \ if\ \{\$properties\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ false\n\ \ \ \ \}\n\ \ \ \ set\ isKeyboard\ \[string\ match\ *ID_INPUT_KEYBOARD=1*\ \$properties\]\n\ \ \ \ return\ \$isKeyboard\n\ \ \ \ #\ TODO:\ Excluding\ mice\ would\ nice\ to\ keey\ the\ list\ of\ keyboard\ devices\ short\n\ \ \ \ #\ \ \ \ \ \ \ Alas,\ including\ mice\ is\ necessary\ for\ the\ Logitech\ K400R\ keyboard\n\ \ \ \ #\ set\ isMouse\ \[string\ match\ *ID_INPUT_MOUSE=1*\ \$properties\]\n\ \ \ \ #\ return\ \[expr\ \{\$isKeyboard\ &&\ !\$isMouse\}\]\n\}\n\n####\n#\ /dev/input/event*\ addresses\ are\ the\ ground\ truth\ for\ keyboard\ devices\n#\n#\ This\ function\ goes\ through\ each\ of\ them\ and\ checks\ if\ they\ are\ keyboards\nproc\ walkInputEventPaths\ \{\}\ \{\n\ \ \ \ #\ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/event*\"\]\n\ \ \ \ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/by-path/*\"\]\n\ \ \ \ set\ keyboards\ \[list\]\n\ \ \ \ foreach\ device\ \$allDevices\ \{\n\ \ \ \ \ \ \ \ if\ \{\[isKeyboard\ \$device\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[file\ readable\ \$device\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"keyboard:\ Device\ \$device\ is\ not\ readable.\ Attempting\ to\ change\ permissions.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Attempt\ to\ change\ permissions\ so\ that\ the\ file\ can\ be\ read\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ chmod\ +r\ \$device\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ keyboards\ \$device\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$keyboards\n\}\n\nset\ keyboardDevices\ \[walkInputEventPaths\]\nforeach\ keyboard\ \$keyboardDevices\ \{\n\ \ \ \ Claim\ \$keyboard\ is\ a\ keyboard\ device\n\}\n\n#\ backwards\ compatibility\nWhen\ /page/\ is\ a\ keyboard\ with\ path\ /keyboard/\ \{\n\ \ \ \ Claim\ \$page\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ us\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ device\ \{\n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/shapes.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/shapes.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/shapes.folk programCode set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octagon\ 8\ nonagon\ 9\]\n\nproc\ process_offset\ \{offset\ region\}\ \{\n\ \ if\ \{!\[info\ exists\ region\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ set\ w\ \[region\ width\ \$region\]\n\ \ set\ h\ \[region\ height\ \$region\]\n\ \ \n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \n\ \ \ \ \ \ !\[string\ match\ *%*\ \$offset\]\ &&\ \n\ \ \ \ \ \ !\[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ simple\ percentage\ string:\ \"50%\"\n\ \ if\ \{\[string\ match\ *%*\ \$offset\]\ &&\ \[llength\ \$offset\]\ ==\ 1\}\ \{\n\ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$offset\]\ /\ 100.0\}\]\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \ #\ Default\ to\ horizontal\ offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ strings:\ \"right\",\ \"left\",\ \"up\",\ \"down\"\n\ \ if\ \{\$offset\ eq\ \"right\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"left\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{-\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"up\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ 0.5\}\]\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"down\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{\$h\ *\ 0.5\}\]\]\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ percentage:\ \"right\ 50%\",\ \"left\ 25%\",\ etc.\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ set\ direction\ \[lindex\ \$offset\ 0\]\n\ \ \ \ set\ amount\ \[lindex\ \$offset\ 1\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$amount\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$amount\]\ /\ 100.0\}\]\n\n\ \ \ \ \ \ switch\ \$direction\ \{\n\ \ \ \ \ \ \ \ \"right\"\ \{\ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"left\"\ \ \{\ return\ \[list\ \[expr\ \{-\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"up\"\ \ \ \ \{\ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ \"down\"\ \ \{\ return\ \[list\ 0\ \[expr\ \{\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ default\ \{\ return\ \[list\ 0\ 0\]\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\ \ \n\ \ #\ Handle\ x\ y\ vector\ where\ one\ or\ both\ components\ have\ percentage\ notation\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\}\ \{\n\ \ \ \ lassign\ \$offset\ ox\ oy\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$ox\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$ox\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ ox\ \[expr\ \{\$w\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$oy\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$oy\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ oy\ \[expr\ \{\$h\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ \[list\ \$ox\ \$oy\]\n\ \ \}\n\ \ \n\ \ #\ Default\ fallback\n\ \ return\ \$offset\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ shape\ with\ /...options/\ \{\n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ color\ white\n\}\n\n#\ Handle\ \"a\"\ vs\ \"an\"\ grammar\ variations\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n\}\ \n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ \{\n\ \ \ \ Wish\ \$p\ draws\ text\ \$text\ with\ color\ white\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\n#\ Pass\ through\ options\ for\ \"an\"\ version\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ with\ /...options/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ \{*\}\$options\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ rect\ with\ width\ /w/\ height\ /h/\ \{\n\ \ Wish\ \$p\ draws\ a\ rect\ with\ width\ \$w\ height\ \$h\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ radius\ /rad/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ radius\ \$rad\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ set\ of\ points\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ polyline\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ Center\ circle\n\ \ Wish\ \$this\ draws\ a\ circle\n\ \ \n\ \ #\ Grid\ of\ shapes\ with\ varying\ thickness\n\ \ set\ baseX\ -850\n\ \ set\ baseY\ -200\n\ \ set\ gridSpacing\ 130\n\n\ \ #\ Row\ 0:\ Title\n\ \ Wish\ \$this\ draws\ text\ \"triangle\"\ with\ color\ skyblue\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"square\"\ with\ color\ green\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"pentagon\"\ with\ color\ gold\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"hexagon\"\ with\ color\ orange\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ \n\ \ #\ Row\ 1:\ Regular\ polygons\ with\ different\ colors\ and\ thickness\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ thickness\ 2\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ thickness\ 4\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ thickness\ 6\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ thickness\ 8\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ \n\ \ #\ Row\ 2:\ Filled\ shapes\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ filled\ true\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\n\ \ #\ Row\ 3:\ Directional\ offset\ examples\ (replacing\ shift)\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ radius\ 40\ offset\ \"right\ 50%\"\ color\ skyblue\n\ \ Wish\ \$this\ draws\ a\ square\ with\ radius\ 40\ offset\ \ \"left\ 50%\"\ color\ green\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ radius\ 40\ offset\ \"up\ 50%\"\ color\ gold\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ radius\ 40\ offset\ \"down\ 50%\"\ color\ orange\n\ \ \n\ \ #\ Row\ 4:\ Rectangles\ with\ different\ properties\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ cyan\ thickness\ 3\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ magenta\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \"right\ 50%\"\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \ \"left\ 50%\"\n\ \ \n#\ Animated\ elements\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ angle\ \$r\]\ angle\n\ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 8\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ offsetVector\ \[list\ \[sin\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\ \[*\ 2\ \[cos\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\]\]\n\ \ \ \ \ \ \ \ \ \ set\ vector\ \[::vec2::scale\ \$offsetVector\ \[+\ \[*\ \$i\ \$i\]\ 15\]\]\n\ \ \ \ \ \ \ \ \ \ Wish\ \$this\ draws\ a\ circle\ with\ radius\ \$i\ color\ palegoldenrod\ offset\ \$vector\n\ \ \ \ \ \ \}\n\ \ \}\n\ \ \n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(sin(\$t)\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[-\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[-\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fillVal\"\ color\ red\n\ \ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(\$t\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[+\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[+\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fill\"\ color\ red\n\ \ \}\n\ \ \n\ \ Wish\ \$this\ is\ outlined\ white\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/tags-to-quads.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/audio.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/audio.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/audio.folk programCode #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n#\ ALSA,\ PulseAudio,\ or\ JACK\ drivers.\n#\n#\ See\ https://miniaud.io/.\ We\ are\ using\ Miniaudio\ v0.11.23.\n#\n#\ Examples:\n#\n#\ Play\ a\ sound\ file\ in\ assets/sounds/\ or\ user-programs/\$hostname/sounds:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ drums.wav\n#\n#\ Play\ a\ sound\ file\ by\ absolute\ path:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ /home/folk/sounds/drums.wav\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/miniaudio\n\nif\ \{!\[catch\ \{exec\ which\ sclang\}\]\}\ \{\n\ \ \ \ #\ HACK:\ We're\ running\ msuic.folk\ and\ therefore\ are\ running\ JACK,\n\ \ \ \ #\ so\ we\ should\ force\ miniaudio\ to\ not\ use\ ALSA\ directly\ (because\n\ \ \ \ #\ that\ won't\ work).\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ MA_NO_ALSA\n\ \ \ \ \ \ \ \ #define\ MA_NO_PULSEAUDIO\n\ \ \ \ \}\n\}\n\$cc\ code\ \{\n\ \ \ #define\ MINIAUDIO_IMPLEMENTATION\n\}\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <stdint.h>\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <miniaudio.h>\n\nif\ \{\$::tcl_platform(os)\ ne\ \"Darwin\"\}\ \{\n\ \ \ \ \$cc\ endcflags\ -lpthread\ -lm\ -ldl\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ ma_context\ \ \ \ \ g_ctx\;\n\ \ \ \ static\ ma_engine\ \ \ \ \ \ g_engine\;\n\ \ \ \ static\ ma_sound_group\ g_group\;\n\n\ \ \ \ static\ bool\ g_ctx_initialized\ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_engine_initialized\ =\ false\;\n\ \ \ \ static\ bool\ g_engine_started\ \ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_group_initialized\ \ =\ false\;\n\n\ \ \ \ static\ pthread_mutex_t\ g_state_mtx\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ typedef\ struct\ SoundNode\ \{\n\ \ \ \ \ \ \ \ ma_sound*\ \ \ \ \ \ \ \ \ snd\;\n\ \ \ \ \ \ \ \ struct\ SoundNode*\ next\;\n\ \ \ \ \}\ SoundNode\;\n\n\ \ \ \ static\ SoundNode*\ \ \ \ \ \ g_head\ \ \ \ \ \ \ \ \ \ \ \ =\ NULL\;\n\ \ \ \ static\ pthread_mutex_t\ g_list_mtx\ \ \ \ \ \ \ \ =\ PTHREAD_MUTEX_INITIALIZER\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ \ =\ false\;\n\ \ \ \ static\ pthread_t\ \ \ \ \ \ \ g_reaper_thr\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ /*\ Maintains\ linked\ list\ of\ active\ sounds\ */\n\ \ \ \ static\ bool\ registry_add(ma_sound*\ snd)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ (SoundNode*)malloc(sizeof\ *node)\;\n\n\ \ \ \ \ \ \ \ if\ (!node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ registry_add:\ alloc\ failed\\n\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ node->snd\ =\ snd\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ node->next\ =\ g_head\;\n\ \ \ \ \ \ \ \ g_head\ =\ node\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Removes\ and\ uninitializes\ all\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void\ registry_clear_locked(void)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ next\ =\ node->next\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (node->snd)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(node)\;\n\ \ \ \ \ \ \ \ \ \ \ \ node\ =\ next\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ g_head\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Background\ thread\ that\ periodically\ removes\ finished\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void*\ reaper_main(void*\ arg)\ \{\n\ \ \ \ \ \ \ \ (void)arg\;\n\n\ \ \ \ \ \ \ \ while\ (!g_shutdown_reaper)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ \ node\ \ =\ g_head\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound*\ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ remove\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (snd\ &&\ !ma_sound_is_playing(snd)\ &&\ !ma_sound_is_looping(snd))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Collect\ finished\ sounds\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remove\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (remove)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(to_free)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ usleep(50\ *\ 1000)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ registry_clear_locked()\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ g_reaper_running\ =\ false\;\n\ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ static\ int\ reaper_start(void)\ \{\n\ \ \ \ \ \ \ \ if\ (g_reaper_running)\ return\ 0\;\n\ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ \ \ \ \ int\ err\ =\ pthread_create(&g_reaper_thr,\ NULL,\ reaper_main,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (err\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ err\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Initializes\ the\ audio\ backend\ and\ sound\ group,\ and\ starts\ the\ reaper\ thread\ */\n\ \ \ \ static\ bool\ audio_init_impl(void)\ \{\n\ \ \ \ \ \ \ \ ma_result\ r\;\n\n\ \ \ \ \ \ \ \ if\ (!g_ctx_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_context_init(NULL,\ 0,\ NULL,\ &g_ctx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ context\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_ctx_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ma_engine_config\ cfg\ =\ ma_engine_config_init()\;\n\ \ \ \ \ \ \ \ \ \ \ \ cfg.pContext\ =\ &g_ctx\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_init(&cfg,\ &g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"miniaudio:\ engine\ initialized\ with\ %s\ backend\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_get_backend_name(g_ctx.backend))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_started)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_start(&g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ start\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_group_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_sound_group_init(&g_engine,\ 0,\ NULL,\ &g_group)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ group\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Unwind\ engine\ on\ group\ failure\;\ context\ remains\ for\ future\ attempts\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_engine_uninit(&g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memset(&g_engine,\ 0,\ sizeof\ g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_group_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ err\ =\ reaper_start()\;\n\n\ \ \ \ \ \ \ \ if\ (err\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"audio:\ reaper\ thread\ create\ failed:\ %d\\n\",\ err)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ audioInit\ \{\}\ bool\ \{\n\ \ \ \ pthread_mutex_lock(&g_state_mtx)\;\n\ \ \ \ bool\ success\ =\ audio_init_impl()\;\n\ \ \ \ pthread_mutex_unlock(&g_state_mtx)\;\n\n\ \ \ \ if\ (success)\ \{\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ERROR(\"miniaudio:\ audio\ init\ failed\\n\")\;\n\ \ \ \ return\ false\;\n\}\n\n\$cc\ proc\ audioStop\ \{ma_sound*\ target\}\ void\ \{\n\ \ \ \ SoundNode*\ to_free\ =\ NULL\;\n\ \ \ \ ma_sound*\ snd\ =\ NULL\;\n\n\ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ /*\ Find\ the\ sound\ to\ stop.\ TODO:\ this\ duplicates\ traversal\ logic\ from\ the\ reaper\ thread\ */\n\ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ if\ (node->snd\ ==\ target)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ node->snd\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ /*\ Sound\ already\ reaped\ or\ never\ registered\ */\n\ \ \ \ if\ (!to_free)\ return\;\n\n\ \ \ \ if\ (snd)\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ snd\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ free(to_free)\;\n\}\n\n\$cc\ proc\ playSound\ \{char*\ path\}\ ma_sound*\ \{\n\ \ \ \ ma_sound*\ snd\ =\ (ma_sound*)malloc(sizeof\ *snd)\;\n\n\ \ \ \ if\ (!snd)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ alloc\ sound\ failed\\n\")\;\n\ \ \ \ \}\n\n\ \ \ \ ma_result\ r\ =\ ma_sound_init_from_file(&g_engine,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MA_SOUND_FLAG_DECODE\ |\ MA_SOUND_FLAG_NO_SPATIALIZATION,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &g_group,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ init\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ r\ =\ ma_sound_start(snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ start\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (!registry_add(snd))\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ registry\ add\ failed\ for\ %s\\n\",\ path)\;\n\ \ \ \ \}\n\n\ \ \ \ fprintf(stderr,\ \"miniaudio:\ playing\ %s\\n\",\ path)\;\n\ \ \ \ return\ snd\;\n\}\n\ntry\ \{\n\ \ \ \ set\ audioLib\ \[\$cc\ compile\]\n\ \ \ \ set\ success\ \[\$audioLib\ audioInit\]\n\n\ \ \ \ if\ \{!\$success\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ init\ failed\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ audio\ library\ is\ \$audioLib\n\}\ on\ error\ e\ \{\n\ \ \ \ puts\ stderr\ \"audio:\ compile\ failed:\ \$e\"\n\}\n\nWhen\ the\ audio\ library\ is\ /audioLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ play\ audio\ /sound/\ \{\n\n\ \ \ \ #\ Check\ if\ the\ sound\ file\ exists\ in\ the\ user-programs/\$hostname/sounds\ directory\n\ \ \ \ #\ or\ in\ the\ working\ directory's\ assets/sounds\ subdirectory.\ Otherwise,\ assume\n\ \ \ \ #\ it's\ an\ absolute\ path.\n\ \ \ \ proc\ resolveSoundPath\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ scriptDir\ \[file\ dirname\ \[info\ script\]\]\n\ \ \ \ \ \ \ \ set\ projectRoot\ \[pwd\]\n\ \ \ \ \ \ \ \ set\ hostname\ \[info\ hostname\]\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/user-programs/\$hostname/audio/\$filename\"\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/audio/\$filename\"\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ #\ treat\ as\ an\ absolute\ path\n\ \ \ \ \ \ \ \ return\ \$filename\n\ \ \ \ \}\n\n\ \ \ \ set\ path\ \[resolveSoundPath\ \$sound\]\n\n\ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ File\ not\ found\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ handle\ \[\$audioLib\ playSound\ \$path\]\n\n\ \ \ \ if\ \{\$handle\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ Failed\ to\ play\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ puts\ \"audio:\ stopping\ audio\ '\$path'\"\n\ \ \ \ \ \ \ \ \$audioLib\ audioStop\ \$handle\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/camera/slice.folk is replaced with /...replacedOpts/ \ ()when /someone/ wishes program builtin-programs/camera/slice.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/camera/slice.folk programCode #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{\n#\ \ \ \ \ Wish\ \$this\ displays\ camera\ slice\ \$slice\n#\ \}\n\n#\ Callback:\ extract\ out\ a\ camera\ slice\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ camera\ slice\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ intrinsics\ /cameraIntrinsics/\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ frame\ /frame/\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ /p/\ has\ quad\ /q/\ \{\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n\}\n\n#\ Auto-trigger\ callback\ for\ `when\ has\ camera\ slice`\ statements\nWhen\ when\ /p/\ has\ camera\ slice\ /slice/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ -nonatomically\ \$p\ has\ camera\ slice\n\}\n\n#\ Display\ a\ camera\ slice\ (for\ backward\ compatibility).\nWhen\ /someone/\ wishes\ /p/\ displays\ camera\ slice\ /slice/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$slice\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/tags-geometry.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/tags-geometry.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/tags-geometry.folk programCode When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ scaled\ by\ x\ /xScale/\ y\ /yScale/\ \{\n\ \ \ \ proc\ extractMm\ \{mm\}\ \{\n\ \ \ \ \ \ \ \ regexp\ \{(\[0-9.\]+)mm\}\ \$mm\ ->\ extracted\n\ \ \ \ \ \ \ \ return\ \$extracted\n\ \ \ \ \}\n\n\ \ \ \ set\ tagSize\ \[extractMm\ \[dict\ get\ \$defaultGeom\ tagSize\]\]\n\ \ \ \ set\ left\ \[extractMm\ \[dict\ get\ \$defaultGeom\ left\]\]\n\ \ \ \ set\ right\ \[extractMm\ \[dict\ get\ \$defaultGeom\ right\]\]\n\ \ \ \ set\ top\ \[extractMm\ \[dict\ get\ \$defaultGeom\ top\]\]\n\ \ \ \ set\ bottom\ \[extractMm\ \[dict\ get\ \$defaultGeom\ bottom\]\]\n\n\ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\n\ \ \ \ set\ right\ \$(\$right\ +\ (\$width\ *\ \$xScale\ -\ \$width))mm\n\ \ \ \ set\ bottom\ \$(\$bottom\ +\ (\$height\ *\ \$yScale\ -\ \$height))mm\n\n\ \ \ \ set\ newGeom\ \[list\ tagSize\ \$\{tagSize\}mm\ left\ \$\{left\}mm\ right\ \$\{right\}mm\ top\ \$\{top\}mm\ bottom\ \$\{bottom\}mm\]\n\n\ \ \ \ Claim\ tag\ \$program\ has\ geometry\ \$newGeom\n\}\n\nWhen\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /tag/\ has\ resolved\ geometry\ \{\n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/title.folk is replaced with /...replacedOpts/ \n\ \ \ ()when /someone/ wishes program builtin-programs/title.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/title.folk programCode #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ titled\ \"This\ is\ a\ tag\"\n#\ Wish\ \$this\ is\ footnoted\ \"This\ is\ a\ footnote\"\n#\ Wish\ \$this\ is\ right-margined\ \"This\ is\ right-margined\ text\"\n#\ Wish\ \$this\ is\ left-margined\ \"This\ is\ left-margined\ text\"\n\nWhen\ /thing/\ has\ quad\ /quad/\ \{\n\ \ \ \ Claim\ -keep\ 50ms\ \$thing\ has\ a\ quad\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /thing/\ has\ a\ quad\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/connections.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/connections.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/connections.folk programCode #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connected\ to\ \$tag2\"\ or\ \"Wish\ \$tag\ is\ dynamically\ connected\ to\ \$tag2\"\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ dynamically\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ sub\ \$sink\ \$source\]\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ grey\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ set\ c\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 2\ color\ \$color\ layer\ \$layer\n\ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ 30\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\}\n\nset\ speed\ 75\nset\ spacing\ 50\nset\ maxsize\ 25\n\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ normalize\ \[vec2\ sub\ \$sink\ \$source\]\]\n\ \ \ set\ distance\ \[vec2\ distance\ \$sink\ \$source\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\ \n\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ lassign\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\ cx\ cy\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 1\ color\ \$color\ layer\ \$layer\n\ \ \ \n\ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ set\ offset\ \[expr\ \{round(\$t*\$speed)\ %\ \$spacing\}\]\n\ \ \ \ \ set\ count\ \[expr\ \{round(\$distance\ /\ \$spacing)\}\]\n\n\ \ \ \ \ for\ \{set\ p\ \$offset\}\ \{\$p\ <\ \$distance\}\ \{incr\ p\ \$spacing\}\ \{\n\ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$source\ \[vec2\ scale\ \$direction\ \$p\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[expr\ \{min(\$maxsize,\ 0.20*min(\$p,\ \$distance\ -\ \$p))\}\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ \$s\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/unix-commands.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/unix-commands.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/unix-commands.folk programCode #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ Wish\ \$this\ runs\ Unix\ command\ \"journalctl\"\ with\ arguments\ \[list\ \"-f\"\ \"-u\"\ \"folk\"\]\nWhen\ /someone/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ with\ arguments\ /args/\ \{\n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n\}\n\n#\ Convenience\ wrapper\ for\ commands\ without\ arguments\nWhen\ /wisher/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ \{\n\tSay\ \$wisher\ wishes\ \$p\ runs\ Unix\ command\ \$command\ with\ arguments\ \[list\]\n\}\n\n#\ When\ /someone/\ wishes\ /p/\ tests\ Unix\ commands\ \{\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"curl\"\ with\ arguments\ \[list\ \"-fsS\"\ \"http://wttr.in/Baltimore?format='%l:+%C'\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"-sSh\"\ \"/home/folk/folk2\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ping\"\ with\ arguments\ \[list\ \"google.com\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"sh\"\ with\ arguments\ \[list\ \"-c\"\ \"while\ :\;\ do\ date\ +%s.%3N\;\ sleep\ 0.5\;\ done\"\]\n\n#\ \t#\ Test\ error\ handling:\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"/nonexistent/path\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"exec\"\ with\ arguments\ \[list\ \"/dev/null\"\]\n\n#\ \tWhen\ \$p\ has\ Unix\ error\ output\ /errorSummary/\ \{\n#\ \t\tputs\ \"errorSummary:\ \$errorSummary\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$errorSummary\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ red\n#\ \t\}\n\n#\ \tWhen\ \$p\ has\ Unix\ output\ lines\ /outputLines/\ \{\n#\ \t\tputs\ \"outputLines:\ \$outputLines\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$outputLines\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ green\n#\ \t\}\n#\ \}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/fswatch.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/fswatch.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/fswatch.folk programCode #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ --recursive\ --event\ Updated\ --event\ Created\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ builtin-programs\ \$::env(HOME)/folk-data/local-program\ \$::env(PWD)/user-programs\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -buffering\ line\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ if\ \{\[gets\ \$fd\ line\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"fswatch:\ fswatch\ failed.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{builtin-programs\\/.*\$\}\ \$line\ changedPath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ changedPath\ \$line\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ changedFilename\ \[file\ tail\ \$changedPath\]\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$changedFilename\ 0\]\ eq\ \".\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$changedFilename\ 0\]\ eq\ \"#\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[file\ extension\ \$changedFilename\]\ ne\ \".folk\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ \"fswatch:\ \$changedPath\ updated,\ ignoring.\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"fswatch:\ \$changedPath\ updated,\ reloading.\"\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$changedPath\ r\]\;\ set\ programCode\ \[read\ \$fp\]\;\ close\ \$fp\n\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 100ms\ -on\ boot.folk\ -key\ \[list\ \$changedPath\ code\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$changedPath\ has\ program\ code\ \$programCode\n\ \ \ \ \}\n\}\ on\ error\ err\ \{\n\ \ \ \ puts\ stderr\ \"fswatch:\ Warning:\ could\ not\ invoke\ `fswatch`\ (\$err).\"\n\ \ \ \ puts\ stderr\ \"fswatch:\ Will\ not\ watch\ builtin-programs\ for\ changes.\"\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/camera/enumerate.folk programCode {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <unistd.h>
$cc include <sys/ioctl.h>
$cc include <linux/videodev2.h>
$cc proc getInfoForCamera {char* camera} Jim_Obj* {
int fd = open(camera, O_RDWR);
FOLK_ENSURE(fd >= 0);
Jim_Obj *infoObj = Jim_NewDictObj(interp, NULL, 0);
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "card", -1),
Jim_NewStringObj(interp, (const char *)cap.card, -1));
}
Jim_Obj *formatsList = Jim_NewListObj(interp, NULL, 0);
// Enumerate pixel formats
struct v4l2_fmtdesc fmt_desc = {0};
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
char fourcc_str[5];
fourcc_str[0] = fmt_desc.pixelformat & 0xFF;
fourcc_str[1] = (fmt_desc.pixelformat >> 8) & 0xFF;
fourcc_str[2] = (fmt_desc.pixelformat >> 16) & 0xFF;
fourcc_str[3] = (fmt_desc.pixelformat >> 24) & 0xFF;
fourcc_str[4] = '\0';
Jim_Obj *resolutionsList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmsizeenum frm_size = {0};
frm_size.pixel_format = fmt_desc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frm_size) == 0) {
if (frm_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Jim_Obj *frameratesList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmivalenum frm_interval = {0};
frm_interval.pixel_format = fmt_desc.pixelformat;
frm_interval.width = frm_size.discrete.width;
frm_interval.height = frm_size.discrete.height;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval) == 0) {
if (frm_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
double fps = (double)frm_interval.discrete.denominator /
frm_interval.discrete.numerator;
Jim_ListAppendElement(interp, frameratesList, Jim_NewDoubleObj(interp, fps));
} else if (frm_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
double min_fps = (double)frm_interval.stepwise.max.denominator /
frm_interval.stepwise.max.numerator;
double max_fps = (double)frm_interval.stepwise.min.denominator /
frm_interval.stepwise.min.numerator;
Jim_Obj *rangeDict = Jim_ObjPrintf("min %f max %f", min_fps, max_fps);
Jim_ListAppendElement(interp, frameratesList, rangeDict);
}
frm_interval.index++;
}
int frameratesLen;
const char *frameratesStr = Jim_GetString(frameratesList, &frameratesLen);
Jim_Obj *resDict = Jim_ObjPrintf("width %u height %u framerates {%s}",
frm_size.discrete.width,
frm_size.discrete.height,
frameratesStr);
Jim_ListAppendElement(interp, resolutionsList, resDict);
}
frm_size.index++;
}
int resolutionsLen;
const char *resolutionsStr = Jim_GetString(resolutionsList, &resolutionsLen);
Jim_Obj *formatDict = Jim_ObjPrintf("fourcc {%s} description {%s} resolutions {%s}",
fourcc_str,
(char*)fmt_desc.description,
resolutionsStr);
Jim_ListAppendElement(interp, formatsList, formatDict);
fmt_desc.index++;
}
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "formats", -1),
formatsList);
close(fd);
return infoObj;
}
set formatsLib [$cc compile]
set camerasByCanonicalName [dict create]
set cameras [glob -nocomplain "/dev/v4l/by-path/*"]
# sort first so the order (and therefore which dedupe wins) is
# consistent across boots.
set cameras [lsort $cameras]
foreach camera $cameras {
# I would prefer to use by-id, but not all cameras show up in
# by-id (webcam on my Dell laptop does not, for instance).
try {
set canonicalName [file readlink $camera]
} on error e {
set canonicalName $camera
}
if {[dict exists $camerasByCanonicalName $canonicalName]} {
# Skip cameras that we already have by another name, so there
# aren't dupes in the enumeration (in particular, by-path
# often has both -usb- and -usbv2- copies of a camera).
continue
}
dict set camerasByCanonicalName $canonicalName $camera
set info [$formatsLib getInfoForCamera $camera]
Claim $::thisNode has camera $camera with {*}$info
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/display-saver.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/display-saver.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/display-saver.folk programCode When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/editor-control.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/editor-control.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/editor-control.folk programCode When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \"/editor-control\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ html\ \{\n<!DOCTYPE\ html>\n<html\ lang=\"en\">\n\ \ \ \ <head>\n\ \ \ \ \ \ \ \ <meta\ charset=\"utf-8\"\ />\n\ \ \ \ \ \ \ \ <title>Editor\ copy/paste</title>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ </head>\n\ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ \ \ \ \ Select\ a\ keyboard:\ <select\ id=\"keyboard-select\"></select>\n\ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"120\"\ rows=\"40\"></textarea>\n\ \ \ \ \ \ \ \ <script>\nconst\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\nconst\ keyboardSelect\ =\ document.querySelector(\"#keyboard-select\")\;\nconst\ textarea\ =\ document.querySelector(\"#code\")\;\n\nvar\ currentKeyboard\ =\ null\;\nvar\ programCode\ =\ \"\"\;\ //\ not\ the\ same\ as\ editor\ code\nvar\ cursorPosition\ =\ \[0,\ 0\]\;\n\n//\ temporarily\ disable\ event\ processing\ after\ sending\ new\ code\ to\ prevent\ recursive\ event\ sends\nvar\ allowLocalEventsToProcess\ =\ true\;\nvar\ allowRemoteEventsToProcess\ =\ true\;\nvar\ _remoteTimoutHandle\;\nvar\ _localTimeoutHandle\;\nfunction\ disableRemoteEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_remoteTimoutHandle)\ clearTimeout(_remoteTimoutHandle)\;\n\ \ \ \ allowRemoteEventsToProcess\ =\ false\;\n\n\ \ \ \ _remoteTimoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowRemoteEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ disableLocalEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_localTimeoutHandle)\ clearTimeout(_localTimeoutHandle)\;\n\ \ \ \ allowLocalEventsToProcess\ =\ false\;\n\n\ \ \ \ _localTimeoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowLocalEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ updateProgramCode()\ \{\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ currentCode\ =\ textarea.value\;\n\ \ \ \ programCode\ =\ currentCode\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{cursorPosition\[0\]\}\ \$\{cursorPosition\[1\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\nfunction\ updateCursorAndCode(ev)\ \{\n\ \ \ \ if\ (!allowLocalEventsToProcess)\ return\;\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ newCode\ =\ ev.target.value\;\n\n\ \ \ \ //\ figure\ out\ cursor\ position\n\ \ \ \ const\ currentPosition\ =\ textarea.selectionStart\;\n\ \ \ \ const\ linesBefore\ =\ newCode.substring(0,\ currentPosition).split(\"\\n\")\;\n\ \ \ \ const\ y\ =\ linesBefore.length\ -\ 1\;\n\ \ \ \ const\ x\ =\ linesBefore\[linesBefore.length\ -\ 1\].length\;\n\n\ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{x\}\ \$\{y\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(programCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(newCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\ntextarea.addEventListener(\"input\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"selectionchange\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"keydown\",\ ev\ =>\ \{\n\ \ \ \ if(ev.keyCode\ ===\ 83\ /*\ s\ */\ &&\ (navigator.platform.match(\"Mac\")\ ?\ ev.metaKey\ :\ ev.ctrlKey))\ \{\n\ \ \ \ \ \ \ \ ev.preventDefault()\;\n\ \ \ \ \ \ \ \ updateProgramCode()\;\n\ \ \ \ \}\n\})\;\n\nvar\ lastKeyboard\;\ //\ to\ clean\ up\ the\ previous\ keyboard\ when\ another\ is\ picked\nasync\ function\ selectKeyboard(\{\ page,\ kbPath\ \})\ \{\n\ \ \ \ if\ (lastKeyboard)\ lastKeyboard.stop()\;\n\n\ \ \ \ currentKeyboard\ =\ \{\ page,\ kbPath\ \}\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ lastKeyboard\ =\ await\ ws.watch(`\$\{id\}\ has\ base64\ editor\ code\ /editorCode/\ program\ code\ /programCode/\ &\ the\ \$\{kbPath\}\ cursor\ is\ /cursor/`,\ \{\n\ \ \ \ \ \ \ \ add:\ (\{\ editorCode,\ programCode:\ _programCode,\ cursor\ \})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (!allowRemoteEventsToProcess)\ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ disableLocalEventProcessing(500)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ programCode\ =\ atob(_programCode)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ editorCode\ =\ atob(editorCode)\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.value\ =\ editorCode\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ figure\ out\ where\ the\ cursor\ is\n\ \ \ \ \ \ \ \ \ \ \ \ let\ \[x,\ y\]\ =\ loadList(cursor)\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ parseInt(x)\;\ y\ =\ parseInt(y)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ const\ lines\ =\ editorCode.split(\"\\n\")\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ let\ pos\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (let\ i\ =\ 0\;\ i\ <\ y\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ lines\[i\].length\ +\ 1\;\ //\ +\ 1\ for\ newline\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ x\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.focus()\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionStart\ =\ pos\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionEnd\ =\ pos\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \})\;\n\}\n\n//\ update\ keyboard\ list\ as\ it\ changes\nws.watchCollected(\"/page/\ is\ an\ editor\ &\ /page/\ is\ a\ keyboard\ with\ path\ /kbPath/\",\ keyboards\ =>\ \{\n\ \ \ \ keyboardSelect.innerHTML\ =\ \"\"\;\n\n\ \ \ \ for\ (let\ keyboard\ of\ keyboards)\ \{\n\ \ \ \ \ \ \ \ let\ \{page,\ kbPath\}\ =\ keyboard\;\n\ \ \ \ \ \ \ \ keyboardSelect.innerHTML\ +=\ `<option\ value=\"\$\{JSON.stringify(keyboard)\}\">\$\{page\}\ (\$\{kbPath\})</option>`\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (keyboards.length\ ===\ 1)\ \{\n\ \ \ \ \ \ \ \ selectKeyboard(keyboards\[0\])\;\n\ \ \ \ \}\n\})\;\n\n//\ fired\ when\ selected\ keyboard\ changes\nkeyboardSelect.addEventListener(\"input\",\ (ev)\ =>\ \{\n\ \ \ \ selectKeyboard(JSON.parse(ev.target.value))\;\n\})\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/image.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/draw/image.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/image.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*jpg\"\ \$im\]\ ||\ \[string\ match\ \"*jpeg\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$jpegLib\ loadJpeg\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ jpegLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ png\ library\ is\ /pngLib/\ \{\n\ \ \ \ fn\ pngLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*png\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$pngLib\ loadPng\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ pngLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ \ \ fn\ gifLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ upvar\ coerceToImage\ coerceToImage\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gif\ \[\$gifLib\ loadGif\ \$im\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$coerceToImage\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \[lindex\ \[dict\ get\ \$gif\ frames\]\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ WARNING:\ This\ is\ not\ an\ Image\ object\ --\ it's\ a\ Gif\n\ \ \ \ \ \ \ \ \ \ \ \ #\ object\ and\ requires\ special\ handling\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$gif\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ gifLoader\]\ is\ an\ image\ loader\n\}\n\n\nWhen\ the\ collected\ results\ for\ \{/loader/\ is\ an\ image\ loader\}\ are\ /loaders/\ \{\n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"image\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.01)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ return\ texColor\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\}\}\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ image\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ displays\ image\ /impath/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n\}\n\nWhen\ /someone/\ wishes\ /p/\ displays\ image\ /im/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ scale\ 1.0\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/apriltags.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ vec4\ background\n\ \ \ \ \ uvec4\ tagBitsVec\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\n\ \ \ \ \ \ \ \ int\ x\ =\ int(uv.x\ *\ 10)\;\ int\ y\ =\ int(uv.y\ *\ 10)\;\n\ \ \ \ \ \ \ \ int\ bitIdx\ =\ y\ *\ 10\ +\ x\;\n\ \ \ \ \ \ \ \ uint\ bit\ =\ (tagBitsVec\[bitIdx\ /\ 32\]\ >>\ (bitIdx\ %\ 32))\ &\ 0x1\;\n\ \ \ \ \ \ \ \ return\ bit\ ==\ 1\ ?\ background\ :\ vec4(0,\ 0,\ 0,\ 1)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /writableTexture/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ AprilTag\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/fill.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/draw/fill.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/fill.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](p0,\ p1,\ p2,\ p0,\ p0,\ p0)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ return\ color\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ \{\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n\nWhen\ /someone/\ wishes\ /page/\ is\ filled\ with\ /...options/\ &\\\n\ \ \ \ \ /page/\ has\ region\ /region/\ \{\n\ \ set\ points\ \[region\ vertices\ \$region\]\n\ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ \{*\}\$options\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/dashed-line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\n\ \ \ \ \ float\ dashlength\ float\ dashoffset\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\n\ \ \ \ \ \ \ \ //\ How\ far\ are\ we\ along\ the\ line?\ (in\ pixels)\n\ \ \ \ \ \ \ \ float\ t\ =\ dot(surfaceXy.xy\ -\ from,\ to\ -\ from)\ /\ l\ +\ dashoffset\;\n\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0\ &&\ floor(mod(t\ /\ dashlength,\ 2.0))\ ==\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ dashed\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/line.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/draw/line.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/line.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/gif.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/draw/gif.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/gif.folk programCode When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/circle.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/draw/circle.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/circle.folk programCode Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ center\ float\ radius\ float\ thickness\ vec4\ color\ int\ filled\}\ \{\n\ \ \ \ \ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ center\ +\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r)\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(surfaceXy.xy\ -\ center)\ -\ radius\;\n\ \ \ \ \ \ \ \ if\ (filled\ ==\ 1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ circle\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/color-map.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/draw/color-map.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/color-map.folk programCode {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr {($color >> 8) & 0xFF}]
set r [expr {($color >> 16) & 0xFF}]
return [list [/ $r 255.0] [/ $g 255.0] [/ $b 255.0] 1.0]
}
set colors {
aliceblue F0F8FF
antiquewhite FAEBD7
aqua 00FFFF
aquamarine 7FFFD4
azure F0FFFF
beige F5F5DC
bisque FFE4C4
black 000000
blanchedalmond FFEBCD
blue 0000FF
blueviolet 8A2BE2
brown A52A2A
burlywood DEB887
cadetblue 5F9EA0
chartreuse 7FFF00
chocolate D2691E
coral FF7F50
cornflowerblue 6495ED
cornsilk FFF8DC
crimson DC143C
cyan 00FFFF
darkblue 00008B
darkcyan 008B8B
darkgoldenrod B8860B
darkgray A9A9A9
darkgreen 006400
darkgrey A9A9A9
darkkhaki BDB76B
darkmagenta 8B008B
darkolivegreen 556B2F
darkorange FF8C00
darkorchid 9932CC
darkred 8B0000
darksalmon E9967A
darkseagreen 8FBC8F
darkslateblue 483D8B
darkslategray 2F4F4F
darkslategrey 2F4F4F
darkturquoise 00CED1
darkviolet 9400D3
deeppink FF1493
deepskyblue 00BFFF
dimgray 696969
dimgrey 696969
dodgerblue 1E90FF
firebrick B22222
floralwhite FFFAF0
forestgreen 228B22
fuchsia FF00FF
gainsboro DCDCDC
ghostwhite F8F8FF
gold FFD700
goldenrod DAA520
gray 808080
green 008000
greenyellow ADFF2F
grey 808080
honeydew F0FFF0
hotpink FF69B4
indianred CD5C5C
indigo 4B0082
ivory FFFFF0
khaki F0E68C
lavender E6E6FA
lavenderblush FFF0F5
lawngreen 7CFC00
lemonchiffon FFFACD
lightblue ADD8E6
lightcoral F08080
lightcyan E0FFFF
lightgoldenrodyellow FAFAD2
lightgray D3D3D3
lightgreen 90EE90
lightgrey D3D3D3
lightpink FFB6C1
lightsalmon FFA07A
lightseagreen 20B2AA
lightskyblue 87CEFA
lightslategray 778899
lightslategrey 778899
lightsteelblue B0C4DE
lightyellow FFFFE0
lime 00FF00
limegreen 32CD32
linen FAF0E6
magenta FF00FF
maroon 800000
mediumaquamarine 66CDAA
mediumblue 0000CD
mediumorchid BA55D3
mediumpurple 9370DB
mediumseagreen 3CB371
mediumslateblue 7B68EE
mediumspringgreen 00FA9A
mediumturquoise 48D1CC
mediumvioletred C71585
midnightblue 191970
mintcream F5FFFA
mistyrose FFE4E1
moccasin FFE4B5
navajowhite FFDEAD
navy 000080
oldlace FDF5E6
olive 808000
olivedrab 6B8E23
orange FFA500
orangered FF4500
orchid DA70D6
palegoldenrod EEE8AA
palegreen 98FB98
paleturquoise AFEEEE
palevioletred DB7093
papayawhip FFEFD5
peachpuff FFDAB9
peru CD853F
pink FFC0CB
plum DDA0DD
powderblue B0E0E6
purple 800080
rebeccapurple 663399
red FF0000
rosybrown BC8F8F
royalblue 4169E1
saddlebrown 8B4513
salmon FA8072
sandybrown F4A460
seagreen 2E8B57
seashell FFF5EE
sienna A0522D
silver C0C0C0
skyblue 87CEEB
slateblue 6A5ACD
slategray 708090
slategrey 708090
snow FFFAFA
springgreen 00FF7F
steelblue 4682B4
tan D2B48C
teal 008080
thistle D8BFD8
tomato FF6347
turquoise 40E0D0
violet EE82EE
wheat F5DEB3
white FFFFFF
whitesmoke F5F5F5
yellow FFFF00
yellowgreen 9ACD32
}
set colorMap [dict create]
foreach {color hex} $colors {
dict set colorMap $color [hexcolor $hex]
}
Claim the color map is $colorMap
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/image/gif-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/image/jpeg-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/draw/text.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/draw/text.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/draw/text.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/image/image-lib.folk is replaced with /...replacedOpts ()when /someone/ wishes program builtin-programs/image/image-lib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/image/image-lib.folk programCode {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width;
uint32_t height;
int components;
uint32_t bytesPerRow;
// Weird: this can be mutated if you want the image to be
// reloaded into the GPU.
uint64_t uniq;
uint8_t* data;
}
# Note that this returns an image whose lifetime is tied to the original image.
$cc proc slice {Image im double x double y double subwidth double subheight} Image {
uint8_t *subdata = im.data + (int)y*im.bytesPerRow + (int)x*im.components;
return (Image) {
.width = (uint32_t)subwidth,
.height = (uint32_t)subheight,
.components = im.components,
.bytesPerRow = im.bytesPerRow,
.data = subdata,
.uniq = im.uniq
};
}
$cc proc imageNew {int width int height int components int uniq} Image {
uint8_t* data = malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data,
.uniq = uniq
};
}
$cc proc imageFree {Image image} void {
free(image.data);
}
# Note that this returns a fresh (copied) image. imVertices are
# coordinates in im, clockwise from top-left.
$cc proc warpQuad {Image im double[4][2] imVertices
int outWidth int outHeight} Image {
if (outWidth <= 0 || outHeight <= 0 ||
outWidth > (int)im.width * 4 || outHeight > (int)im.height * 4) {
FOLK_ERROR("warpQuad: bad dimensions %d x %d (source %d x %d)",
outWidth, outHeight, im.width, im.height);
}
Image out = imageNew(outWidth, outHeight, im.components, im.uniq);
// imVertices are clockwise from top-left: [TL, TR, BR, BL]
double tlX = imVertices[0][0], tlY = imVertices[0][1];
double trX = imVertices[1][0], trY = imVertices[1][1];
double brX = imVertices[2][0], brY = imVertices[2][1];
double blX = imVertices[3][0], blY = imVertices[3][1];
// For each output pixel, find corresponding source pixel using bilinear mapping
double invW = (outWidth > 1) ? 1.0 / (outWidth - 1) : 0.0;
double invH = (outHeight > 1) ? 1.0 / (outHeight - 1) : 0.0;
for (int y = 0; y < outHeight; y++) {
// Hoist v and y-dependent edge coords outside x-loop
double v = y * invH;
double leftX = tlX + v * (blX - tlX);
double leftY = tlY + v * (blY - tlY);
double rightX = trX + v * (brX - trX);
double rightY = trY + v * (brY - trY);
double stepX = (rightX - leftX) * invW;
double stepY = (rightY - leftY) * invW;
uint8_t *dstRow = out.data + y * out.bytesPerRow;
double srcX = leftX, srcY = leftY;
for (int x = 0; x < outWidth; x++, srcX += stepX, srcY += stepY) {
uint8_t *dstPixel = dstRow + x * out.components;
int ix = (int)srcX;
int iy = (int)srcY;
// Fixed-point fractions (0..255)
int fx = (int)((srcX - ix) * 256);
int fy = (int)((srcY - iy) * 256);
if (ix >= 0 && ix < (int)im.width - 1 && iy >= 0 && iy < (int)im.height - 1) {
uint8_t *p00 = im.data + iy * im.bytesPerRow + ix * im.components;
uint8_t *p10 = p00 + im.components;
uint8_t *p01 = p00 + im.bytesPerRow;
uint8_t *p11 = p01 + im.components;
for (int c = 0; c < im.components; c++) {
int top = p00[c] + ((fx * (p10[c] - p00[c])) >> 8);
int bot = p01[c] + ((fx * (p11[c] - p01[c])) >> 8);
dstPixel[c] = (uint8_t)(top + ((fy * (bot - top)) >> 8));
}
} else if (ix >= 0 && ix < (int)im.width && iy >= 0 && iy < (int)im.height) {
uint8_t *srcPixel = im.data + iy * im.bytesPerRow + ix * im.components;
for (int c = 0; c < im.components; c++) {
dstPixel[c] = srcPixel[c];
}
} else {
for (int c = 0; c < im.components; c++) {
dstPixel[c] = 0;
}
}
}
}
return out;
}
set imageLib [$cc compile]
Claim the image library is $imageLib
fn defineImageArgtype {uvx} {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
}
Claim the image uvx argtype definer is [fn defineImageArgtype]
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/image/png-lib.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/image/png-lib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/image/png-lib.folk programCode {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/dep-graph.folk programCode set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ create\]\n\ \ \ \ foreach\ stmt\ \[Query!\ /...anything/\]\ \{\n\ \ \ \ \ \ \ \ set\ stmtRef\ \[dict\ get\ \$stmt\ __ref\]\n\ \ \ \ \ \ \ \ set\ label\ \[\$dbLib\ clause\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ label\ \[join\ \[lmap\ line\ \[split\ \$label\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ set\ label\ \[string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$label\]\]\n\ \ \ \ \ \ \ \ set\ stmtParentCount\ \[\$dbLib\ statementParentCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ stmtPtrCount\ \[\$dbLib\ statementPtrCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ \\\[label=\\\"\$stmtRef\ (\$stmtParentCount\ parents)\ (\$stmtPtrCount\ ptrs):\ \$label\\\"\\\]\;\"\n\n\ \ \ \ \ \ \ \ foreach\ childMatchRef\ \[\$dbLib\ childMatches\ \$db\ \$stmtRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ ->\ <\$childMatchRef>\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ matchRefs\ \$childMatchRef\ true\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ foreach\ \{matchRef\ _\}\ \$matchRefs\ \{\n\ \ \ \ \ \ \ \ set\ match\ \[\$dbLib\ matchAcq\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ if\ \{\$match\ eq\ \"(Match*)\ 0x0\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ set\ matchPtrCount\ \[\$dbLib\ matchPtrCount\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ set\ matchIsAlive\ \[\$dbLib\ matchIsAlive\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ \\\[label=\\\"\$matchRef\ (alive?\ \$matchIsAlive)\ (\$matchPtrCount)\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ childStatementRef\ \[\$dbLib\ childStatements\ \$db\ \$matchRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ ->\ <\$childStatementRef>\;\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$dbLib\ matchRel\ \$db\ \$match\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[join\ \$dot\ \"\\n\"\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWhen\ the\ db\ library\ is\ /dbLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/print/print.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/print/print.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/print/print.folk programCode #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ from\ the\ Web\ UI,\ or\ declare\ it\ using\ Folk:\n#\n#\ \ \ \ \ Assert\ \$::thisNode\ claims\ printer\ \"printer-name\"\ is\ a\ cups\ printer\ with\ url\ \"http://url/ipp/print\"\ driver\ \"everywhere\"\n#\n#\ Lastly,\ you\ need\ to\ declare\ a\ default\ printer\ and\ default\ paper\ format:\n#\ (make\ sure\ that\ the\ default\ printer\ supports\ the\ default\ paper\ format)\n#\n#\ \ \ \ \ Claim\ printer\ my-printer\ is\ the\ default\ printer\n#\ \ \ \ \ Claim\ paper\ format\ a4\ is\ the\ default\ paper\ format\n\nClaim\ the\ paper\ formats\ are\ \{\n\ \ \ \ letter\ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\ \ \ \ a4\ \ \ \ \ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{595\ 842\}\}\n\ \ \ \ indexcard\ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\}\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n\}\n\nSubscribe:\ print\ pdf\ /pdfPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/nav.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/web/nav.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/nav.folk programCode {When the collected results for [list /someone/ wishes the web server handles route /route/ with /...options/] are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/block-stats.folk is replaced with /...replacedOpts ()when /someone/ wishes program builtin-programs/web/block-stats.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/block-stats.folk programCode {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/textures.folk is replaced with /...replacedOpts/ \ ()when /someone/ wishes program builtin-programs/web/textures.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/textures.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ draw\ library\ is\ /drawLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ endcflags\ -lpng\n\ \ \ \ \$cc\ cflags\ -I./vendor\n\ \ \ \ \$cc\ endcflags\ \$vmaDll\n\ \ \ \ \$cc\ include\ <png.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ \ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ \ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ to\ make\ gpuLib\ extend\ properly\n\ \ \ \ \$cc\ typedef\ \{struct\ PushConstantsEncoder\}\ PushConstantsEncoder\n\ \ \ \ \$cc\ typedef\ \{struct\ Pipeline\}\ Pipeline\n\ \ \ \ \$cc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\ \ \ \ \$cc\ argtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ \ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ rtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ char\ buf\[100\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ extend\ \$gpuLib\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ extend\ \$gpuTextureLib\n\ \ \ \ \$cc\ proc\ texturesLibInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ volkInitialize()\;\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyTextureFromGpu\ \{GpuTextureHandle\ han\}\ Image\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ getGpuTexture(han)\;\n\ \ \ \ \ \ \ \ if\ (!block->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (Image)\{0\}\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ block->width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ block->height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\ //\ HACK:\ hard-coded\ for\ now\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ block->width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ malloc(block->width\ *\ block->height\ *\ 4)\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ size_t\ stagingBufferSize\ =\ block->width\ *\ block->height\ *\ 4\;\n\ \ \ \ \ \ \ \ createBuffer(stagingBufferSize,\ VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &stagingBuffer,\ &stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n\ \ \ \ \ \ \ \ \ \ \ \ .oldLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .image\ =\ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseMipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.levelCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ image\ to\ buffer\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferOffset\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferRowLength\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferImageHeight\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.mipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageOffset\ =\ \{0,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ .imageExtent\ =\ \{block->width,\ block->height,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdCopyImageToBuffer(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ ®ion\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ image\ layout\ back\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ VkFence\ fence\ =\ getFence()\;\n\ \ \ \ \ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ staging\ buffer\ back\ to\ CPU\n\ \ \ \ \ \ \ \ void*\ data\;\n\ \ \ \ \ \ \ \ vmaMapMemory(vmaGetAllocator(),\ stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ memcpy(im.data,\ data,\ stagingBufferSize)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ //\ Cleanup\ staging\ buffer\n\ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\ stagingBuffer,\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ struct\ WriteState\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ buffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t*\ size\;\ \n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ void\ pngWriteCallback(png_structp\ png_ptr,\ png_bytep\ data,\ png_size_t\ length)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ WriteState*\ state\ =\ (struct\ WriteState*)png_get_io_ptr(png_ptr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(state->buffer\ +\ *state->size,\ data,\ length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ *state->size\ +=\ length\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ imageToPngBuffer\ \{Image\ im\ size_t*\ outSize\}\ uint8_t*\ \{\n\ \ \ \ \ \ \ \ size_t\ bufferSize\ =\ im.width\ *\ im.height\ *\ im.components\ *\ 2\;\ //\ max\ size\ estimate\n\ \ \ \ \ \ \ \ uint8_t*\ buffer\ =\ malloc(bufferSize)\;\n\ \ \ \ \ \ \ \ *outSize\ =\ 0\;\n\n\ \ \ \ \ \ \ \ png_structp\ png_w\ =\ png_create_write_struct(PNG_LIBPNG_VER_STRING,\ NULL,\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (!png_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_infop\ info_w\ =\ png_create_info_struct(png_w)\;\n\ \ \ \ \ \ \ \ if\ (!info_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ struct\ WriteState\ state\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .buffer\ =\ buffer,\n\ \ \ \ \ \ \ \ \ \ \ \ .size\ =\ outSize\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ png_set_write_fn(png_w,\ &state,\ pngWriteCallback,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGBA,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGB,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_bytep*\ row_pointers\ =\ malloc(sizeof(png_bytep)\ *\ im.height)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ row_pointers\[y\]\ =\ im.data\ +\ y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_set_rows(png_w,\ info_w,\ row_pointers)\;\n\ \ \ \ \ \ \ \ png_write_png(png_w,\ info_w,\ PNG_TRANSFORM_IDENTITY,\ NULL)\;\n\n\ \ \ \ \ \ \ \ free(row_pointers)\;\n\ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\n\ \ \ \ \ \ \ \ *outSize\ =\ bufferSize\;\n\ \ \ \ \ \ \ \ return\ buffer\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyAllTexturesFromGpu\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (getGpuTexture(i)->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Image\ im\ =\ copyTextureFromGpu(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pngSize\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ pngData\ =\ imageToPngBuffer(im,\ &pngSize)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_ObjPrintf(\"Image\ %d\ (%d\ x\ %d)\",\ i,\ im.width,\ im.height))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_NewStringObj(interp,\ (char*)pngData,\ pngSize))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(pngData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(im.data)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ set\ texturesLib\ \[\$cc\ compile\]\n\ \ \ \ \$texturesLib\ texturesLibInit\n\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/textures\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ package\ require\ base64\n\n\ \ \ \ \ \ \ \ set\ images\ \[\$texturesLib\ copyAllTexturesFromGpu\]\n\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>Textures</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ img\ \{\ max-width:\ 100%\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{description\ imageData\}\ \$images\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ b64\ \[binary\ encode\ base64\ \$imageData\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \{<div><p>%s</p><img\ src=\"data:image/png\;base64,%s\"></div>\}\ \$description\ \$b64\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/setup.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/setup.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/setup.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handler\ \{\n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/program.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/web/program.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/program.folk programCode {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/holds.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/holds.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/holds.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/db-lib.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/db-lib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/db-lib.folk programCode {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
$cc include "db.h"
$cc include "common.h"
$cc include "vendor/stb_ds.h"
$cc code {
typedef struct ListOfEdgeTo {
size_t capacityEdges;
size_t nEdges; // This is an estimate.
uint64_t edges[];
} ListOfEdgeTo;
typedef struct GenRc {
int16_t rc;
int gen: 15;
bool alive: 1;
} GenRc;
#include <pthread.h>
}
set dbCFd [open "db.c" r]; set dbC [read $dbCFd]; close $dbCFd
$cc code [lindex [regexp -inline {typedef struct Destructor \{.*\} Destructor;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct DestructorSet \{.*\} DestructorSet;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Statement \{.*\} Statement;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Match \{.*\} Match;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Hold \{.*\} Hold;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct StatementRefList \{.*\} StatementRefList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersionList \{.*\} AtomicallyVersionList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersion \{.*\} AtomicallyVersion;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Atomically \{.*\} Atomically;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Db \{.*\} Db;} $dbC] 0]
$cc argtype StatementRef { StatementRef $argname; sscanf(Jim_String($obj), "s%d:%d", &$argname.idx, &$argname.gen); }
$cc argtype MatchRef { MatchRef $argname; sscanf(Jim_String($obj), "m%d:%d", &$argname.idx, &$argname.gen); }
$cc proc clauseToJimObj {Clause* clause} Jim_Obj* {
Jim_Obj* termObjs[clause->nTerms];
for (int i = 0; i < clause->nTerms; i++) {
termObjs[i] = Jim_NewStringObj(interp, termPtr(clause->terms[i]),
termLen(clause->terms[i]));
}
return Jim_NewListObj(interp, termObjs, clause->nTerms);
}
$cc proc statementParentCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
int ret = stmt->parentCount;
statementRelease(db, stmt);
return ret;
}
$cc proc statementPtrCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
GenRc genRc = stmt->genRc;
int ret = genRc.rc - 1;
statementRelease(db, stmt);
return ret;
}
$cc proc clause {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewStringObj(interp, "(null)", -1); }
Jim_Obj* ret = clauseToJimObj(statementClause(stmt));
statementRelease(db, stmt);
return ret;
}
$cc proc childMatches {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewEmptyStringObj(interp); }
pthread_mutex_lock(&stmt->childMatchesMutex);
if (stmt->childMatches == NULL) {
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[stmt->childMatches->nEdges];
for (int i = 0; i < stmt->childMatches->nEdges; i++) {
MatchRef child = { .val = stmt->childMatches->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("m%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc matchAcq {Db* db MatchRef matchRef} Match* {
return matchAcquire(db, matchRef);
}
$cc proc matchRel {Db* db Match* match} void {
matchRelease(db, match);
}
$cc proc matchPtrCount {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int ret = genRc.rc - 1;
matchRelease(db, match);
return ret;
}
$cc proc matchIsAlive {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int alive = genRc.alive;
matchRelease(db, match);
return alive;
}
$cc code {
#define CHILD_STATEMENTS_REMOVING ((ListOfEdgeTo*)1)
}
$cc proc childStatements {Db* db MatchRef matchRef} Jim_Obj* {
Match* match = matchAcquire(db, matchRef);
if (match == NULL) { return Jim_NewStringObj(interp, "", -1); }
pthread_mutex_lock(&match->childStatementsMutex);
if (match->childStatements == NULL ||
match->childStatements == CHILD_STATEMENTS_REMOVING) {
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[match->childStatements->nEdges];
for (int i = 0; i < match->childStatements->nEdges; i++) {
StatementRef child = { .val = match->childStatements->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("s%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc countAliveStatements {Db* db} int {
int count = 0;
for (int i = 1; i < 65536; i++) { // slot 0 is reserved
GenRc genRc = db->statementPool[i].genRc;
if (genRc.alive) {
count++;
}
}
return count;
}
$cc proc holds {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->holdsMutex);
for (int i = 0; i < shlen(db->holds); i++) {
Hold* hold = &db->holds[i];
Statement* stmt = statementAcquire(db, hold->statement);
if (stmt == NULL) {
fprintf(stderr, "db-lib: holds: WARNING: held statement on (%s) is invalid! (s%d:%d)\n",
hold->key, hold->statement.idx, hold->statement.gen);
continue;
}
char* clauseStr = clauseToString(statementClause(stmt));
Jim_Obj* holdObjv[] = {
Jim_NewStringObj(interp, hold->key, -1),
Jim_NewIntObj(interp, hold->version),
Jim_ObjPrintf("s%d:%d", hold->statement.idx, hold->statement.gen),
Jim_NewStringObj(interp, clauseStr, -1)
};
statementRelease(db, stmt);
free(clauseStr);
Jim_Obj* holdObj = Jim_NewListObj(interp, holdObjv,
sizeof(holdObjv)/sizeof(holdObjv[0]));
Jim_ListAppendElement(interp, retObj, holdObj);
}
mutexUnlock(&db->holdsMutex);
return retObj;
}
$cc proc atomicallys {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->atomicallysMutex);
for (int i = 0; i < sizeof(db->atomicallys)/sizeof(db->atomicallys[0]); i++) {
Atomically* atomically = &db->atomicallys[i];
if (atomically->key == NULL) { continue; }
// Count versions in allVersions list
int versionCount = 0;
AtomicallyVersionList* vl = atomically->allVersions;
while (vl != NULL) {
versionCount++;
vl = vl->next;
}
// Get latest converged version info
int latestConvergedNumber = -1;
if (atomically->latestConvergedVersion != NULL) {
latestConvergedNumber = atomically->latestConvergedVersion->number;
}
Jim_Obj* atomicallyObjv[] = {
Jim_NewStringObj(interp, atomically->key, -1),
Jim_NewIntObj(interp, latestConvergedNumber),
Jim_NewIntObj(interp, versionCount)
};
Jim_Obj* atomicallyObj = Jim_NewListObj(interp, atomicallyObjv,
sizeof(atomicallyObjv)/sizeof(atomicallyObjv[0]));
Jim_ListAppendElement(interp, retObj, atomicallyObj);
}
mutexUnlock(&db->atomicallysMutex);
return retObj;
}
return [$cc compile]
}}]
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/threads.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/web/threads.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/threads.folk programCode set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ -I./vendor/tracy/public\n\ \ \ \ \$cc\ include\ \"workqueue.h\"\n\ \ \ \ \$cc\ include\ \"common.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ extern\ ThreadControlBlock\ threads\[\]\;\n\ \ \ \ \ \ \ \ extern\ int\ _Atomic\ threadCount\;\n\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ int\ unsafe_workQueueCopy(WorkQueueItem*\ into,\ int\ maxn,\ WorkQueue*\ q)\;\n\ \ \ \ \ \ \ \ extern\ void\ traceItem(char*\ buf,\ size_t\ bufsz,\ WorkQueueItem\ item)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ itemToStringObj(WorkQueueItem\ item)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ char\ buf\[10000\]\;\ traceItem(buf,\ sizeof(buf),\ item)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerTids\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ //\ Fallback\ on\ macOS,\ where\ we\ don't\ have\ /proc\ to\ query\ all\n\ \ \ \ \ \ \ \ //\ threads\ of\ the\ Folk\ process.\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ threads\[i\].tid))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfo\ \{int\ threadIndex\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ if\ (threadIndex\ >=\ threadCount\ ||\ threads\[threadIndex\].tid\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ThreadControlBlock\ *thread\ =\ &threads\[threadIndex\]\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ thread->currentItem\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\ Jim_NewStringObj(interp,\ \"op\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(item))\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ items\[100\]\;\n\ \ \ \ \ \ \ \ int\ nitems\ =\ unsafe_workQueueCopy(items,\ 100,\ thread->workQueue)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ workQueueObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nitems\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ workQueueObj,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(items\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"workQueue\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ workQueueObj)\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"isDeactivated\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ thread->isDeactivated))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"currentItemStartTimestamp\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ObjPrintf(\"%\"\ PRId64,\ thread->currentItemStartTimestamp))\;\n\n\ \ \ \ \ \ \ \ int64_t\ now\ =\ timestamp_get(thread->clockid)\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"elapsed\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ (double)(now\ -\ thread->currentItemStartTimestamp)\ /\ 1000.0))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_allocs\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_allocs))\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_frees\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_frees))\;\n\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfoFromTid\ \{int\ tid\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ ==\ tid)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ workerInfo(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #include\ \"vendor/c11-queues/mpmc_queue.h\"\n\ \ \ \ \ \ \ \ extern\ struct\ mpmc_queue\ globalWorkQueue\;\n\ \ \ \ \ \ \ \ extern\ _Atomic\ int\ globalWorkQueueSize\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ globalWorkQueueAvailable\ \{\}\ size_t\ \{\n\ \ \ \ \ \ \ \ return\ mpmc_queue_available(&globalWorkQueue)\;\n\ \ \ \ \}\n\ \ \ \ #\ Unsafely\ peeks\ at\ the\ queue.\n\ \ \ \ \$cc\ proc\ globalWorkQueueItems\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj\ *ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ size_t\ head\ =\ globalWorkQueue.head\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ head\;\ i\ <\ globalWorkQueue.tail\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ mpmc_queue_cell\ *cell\ =\ &globalWorkQueue.buffer\[i\ &\ globalWorkQueue.buffer_mask\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ *ptr\ =\ cell->data\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ *ptr\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ itemToStringObj(item))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nWish\ the\ web\ server\ handles\ route\ \"/threads\"\ with\ handler\ \{\n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/web.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/web/web.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/web.folk programCode try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ so\ closing\ a\ tab\ doesn't\ crash\ Folk,\ but\n#\ we\ don't\ want\ to\ block/ignore,\ because\ that\ will\ cause\ child\n#\ processes\ to\ also\ block/ignore\ and\ behave\ weirdly.\nsignal\ handle\ SIGPIPE\n\n#\ To\ force\ a\ rebuild:\ rm\ vendor/wslay/Makefile\nif\ \{!\[file\ exists\ vendor/wslay/Makefile\]\}\ \{\n\ \ \ \ puts\ \"web:\ Configuring\ libwslay...\"\n\ \ \ \ exec\ sh\ -c\ \{cd\ vendor/wslay\ &&\ autoreconf\ -i\ &&\ automake\ &&\ autoconf\ &&\ ./configure\}\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"web:\ Building\ libwslay...\"\nexec\ make\ -C\ vendor/wslay\ >@stdout\ 2>@stderr\nputs\ \"web:\ libwslay\ built.\"\n\nsource\ \"lib/ws.tcl\"\n#\ We\ export\ wsLib\ so\ that\ other\ threads\ can\ emit\ messages\ onto\n#\ websockets.\nClaim\ the\ websocket\ library\ is\ \$wsLib\n\nproc\ handleConnect\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ timeout\ 2000\n\ \ \ \ fileevent\ \$chan\ readable\ \[list\ apply\ \{\{chan\ addr\}\ \{\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleRead\ \$chan\ \$addr\n\ \ \ \ \ \ \ \ \}\ on\ signal\ \{sig\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$sig\ on\ \$chan\ \$addr\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$chan\ \$addr\]\n\}\n\nproc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\nproc\ readFile\ \{filename\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\;\ close\ \$fd\;\ return\ \$response\n\}\n\nproc\ headerGet\ \{headers\ name\ args\}\ \{\n\ \ \ \ foreach\ \{k\ v\}\ \$headers\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ -nocase\ \$k\ \$name\]\}\ \{\ return\ \$v\ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[llength\ \$args\]\ >\ 0\}\ \{\ return\ \[lindex\ \$args\ 0\]\ \}\n\ \ \ \ error\ \"missing\ HTTP\ header\ \$name\"\n\}\n\nproc\ handlePage\ \{path\ httpStatusVar\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ switch\ -exact\ --\ \$path\ \{\n\ \ \ \ \ \ \ \ \"/favicon.ico\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"image/x-icon\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/favicon.ico\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/style.css\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/css\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/style.css\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/lib/folk.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"lib/folk.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/vendor/idiomorph.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"vendor/idiomorph.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ \$httpStatusVar\ httpStatus\n\ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 404\ Not\ Found\"\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <b>\$path</b>\ Not\ found.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ parseQueryString\ \{queryString\}\ \{\n\ \ \ \ set\ QUERY\ \[dict\ create\]\n\ \ \ \ if\ \{\$queryString\ eq\ \"\"\}\ \{\ return\ \$QUERY\ \}\n\n\ \ \ \ set\ queryString\ \[string\ range\ \$queryString\ 1\ end\]\n\ \ \ \ foreach\ pair\ \[split\ \$queryString\ &\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^=\]*)=(.*)\$\}\ \$pair\ ->\ key\ value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ URL\ decode\ key\ and\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$key\ \{\ \}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$key\ \{\[format\ %c\ 0x\\1\]\}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[subst\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$value\ \{\ \}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$value\ \{\[format\ %c\ 0x\\1\]\}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[subst\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ QUERY\ \$key\ \$value\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$QUERY\n\}\n\nfn\ HtmlWhen\ args\ \{\n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n\}\n\nproc\ handleRead\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ buffering\ none\n\n\ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ set\ firstline\ \$line\n\n\ \ \ \ #\ puts\ \"Http\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%H:%M:%S\"\]):\ \$chan\ \$addr:\ \$line\"\n\ \ \ \ set\ headers\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ \ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{\ break\ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ Http:\ (\$line)\"\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^\\s:\]+)\\s*:\\s*(.+)\}\ \$line\ ->\ k\ v\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ headers\ \$k\ \$v\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ stderr\ \"Http:\ Weird\ line:\ \$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[regexp\ \{GET\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\ &&\ \$path\ ne\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ set\ response\ \{\}\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ForEach!\ /someone/\ wishes\ the\ web\ server\ handles\ route\ /route/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ handler\ \[dict\ get\ \$options\ handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[regexp\ -inline\ ^\$\{route\}(\\\\?.*)?\$\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$vars\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ queryString\ \[lindex\ \$vars\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ QUERY\ \[parseQueryString\ \$queryString\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^html\ \[proc\ html\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ text/html\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^json\ \[proc\ json\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ application/json\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$handler\ 0\]\ eq\ \"applyBlock\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ create\ QUERY\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$vars\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ \$i\ \[lindex\ \$vars\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ handler\ 2\ \[linsert\ \[lindex\ \$handler\ 2\]\ end\ \$env\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[\{*\}\$handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varNames\ \[lseq\ \[llength\ \$vars\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ varNames\ QUERY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[apply\ \[list\ \$varNames\ \$handler\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$vars\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$response\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[handlePage\ \$path\ httpStatus\ contentType\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"\$httpStatus\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$response\ statusAndHeaders\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Response\ not\ generated\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ \{err\ opts\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errorInfo\ \[dict\ get\ \$opts\ -errorinfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ src\ \[lindex\ \$errorInfo\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Web\ error\ in\ \$src\ (\$path):\ \$err\\n\ \ \[errorInfo\ \$err\ \$errorInfo\]\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text-html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>folk:\ 500\ Internal\ Server\ Error</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \$err\]:\n\[htmlEscape\ \[errorInfo\ \$err\ \$errorInfo\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 500\ Internal\ Server\ Error\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ statusAndHeaders\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$response\ body\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[regexp\ \{POST\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\}\ \{\n\ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ set\ contentType\ \"text/plain\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"\$httpStatus\\r\\nConnection:\ close\\r\\nContent-Type:\ \$contentType\\r\\n\\r\\n\"\n\n\ \ \ \ \ \ \ \ set\ body\ \[\$chan\ read\ \[headerGet\ \$headers\ Content-Length\]\]\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ (\$body)\"\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[eval\ \$body\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[info\ exists\ path\]\ &&\ \$path\ eq\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"web:\ Request\ for\ /ws\ (\$headers)\"\n\ \ \ \ \ \ \ \ set\ clientKey\ \[headerGet\ \$headers\ Sec-WebSocket-Key\ \"\"\]\n\ \ \ \ \ \ \ \ if\ \{\$clientKey\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"HTTP/1.1\ 400\ Bad\ Request\\r\\nConnection:\ close\\r\\nContent-Type:\ text/plain\;\ charset=utf-8\\r\\n\\r\\nMissing\ Sec-WebSocket-Key\\r\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ WsConnection\ upgrade\ \$chan\ \$clientKey\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ Retract!\ websocket\ \$chan\ is\ connected\]\n\ \ \ \ \ \ \ \ Assert!\ websocket\ \$chan\ is\ connected\n\n\ \ \ \ \}\ else\ \{\ puts\ \"Closing:\ \$chan\ \$addr\ \$headers\"\;\ close\ \$chan\ \}\n\}\n\nwhile\ true\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[socket\ stream.server\ 4273\]\n\ \ \ \ \ \ \ \ \$f\ listen\ 128\n\ \ \ \ \ \ \ \ \$f\ readable\ \[lambda\ \{\}\ \{f\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ client\ \[\$f\ accept\ addr\]\n\ \ \ \ \ \ \ \ \ \ \ \ handleConnect\ \$client\ \$addr\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ break\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ #\ Handles\ failure\ to\ bind\ to\ :4273.\ We\ try\ again\ in\ a\ second.\n\ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$e\"\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\nvwait\ forever\n\n\}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ puts\ \$::realStderr\ \"WARNING:\ web.folk\ failed\ to\ initialize\;\nthe\ web\ server\ is\ probably\ down\;\ check\ /var/tmp/folk-\[pid\]/\ for\ log\ files.\n(Make\ sure\ libtool\ and\ autoconf-archive\ are\ installed.)\n------------------------------------------\n\[errorInfo\ \$e\]\"\n\ \ \ \ return\ -options\ \$opts\ \$e\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/quads.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/quads.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/quads.folk programCode {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/statements.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/web/statements.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/statements.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/keyboards.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/web/keyboards.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/keyboards.folk programCode {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/trie-graph.folk programCode set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ \ \ \ \$cc\ include\ <stdlib.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\ \ \ \ \$cc\ include\ \"trie.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ Db\ Db\;\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ void\ dbLockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ void\ dbUnlockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ Trie*\ dbGetClauseToStatementRef(Db*\ db)\;\n\n#ifdef\ TRACY_ENABLE\n\n#include\ <string.h>\nvoid\ *tmalloc(size_t\ sz)\ \{\n\ \ \ \ void\ *ptr\ =\ malloc(sz)\;\n\ \ \ \ TracyCAllocS(ptr,\ sz,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nvoid\ *tcalloc(size_t\ s1,\ size_t\ s2)\ \{\n\ \ \ \ void\ *ptr\ =\ calloc(s1,\ s2)\;\n\ \ \ \ TracyCAllocS(ptr,\ s1\ *\ s2,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nchar\ *tstrdup(const\ char\ *s0)\ \{\n\ \ \ \ int\ sz\ =\ strlen(s0)\ +\ 1\;\n\ \ \ \ char\ *s\ =\ tmalloc(sz)\;\n\ \ \ \ memcpy(s,\ s0,\ sz)\;\n\ \ \ \ return\ s\;\n\}\nvoid\ tfree(void\ *ptr)\ \{\n\ \ \ \ TracyCFreeS(ptr,\ 4)\;\n\ \ \ \ free(ptr)\;\n\}\n\n#else\n\n#define\ tmalloc\ malloc\n#define\ tcalloc\ calloc\n#define\ tstrdup\ strdup\n#define\ tfree\ free\n\n#endif\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ tclify\ \{Trie*\ trie\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ objc\ =\ 3\ +\ trie->branchesCount\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ objv\[objc\]\;\n\ \ \ \ \ \ \ \ objv\[0\]\ =\ Jim_ObjPrintf(\"x%\"\ PRIxPTR,\ (uintptr_t)\ trie)\;\n\ \ \ \ \ \ \ \ objv\[1\]\ =\ trie->key\ ?\ Jim_ObjPrintf(\"%s\",\ trie->key)\ :\ Jim_ObjPrintf(\"ROOT\")\;\n\ \ \ \ \ \ \ \ objv\[2\]\ =\ trie->value\ ?\ Jim_ObjPrintf(\"%\"PRIu64,\ trie->value)\ :\ Jim_ObjPrintf(\"NULL\")\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ trie->branchesCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ HACK:\ const\ isn't\ supported\ yet,\ so\ have\ to\ cast.\n\ \ \ \ \ \ \ \ \ \ \ \ objv\[3+i\]\ =\ trie->branches\[i\]\ ?\ tclify((Trie\ *)trie->branches\[i\])\ :\ Jim_NewStringObj(interp,\ \"\",\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ objv,\ objc)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ dbTrieTclify\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ dbLockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Trie*\ trie\ =\ dbGetClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ tclify(trie)\;\n\ \ \ \ \ \ \ \ dbUnlockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ jimObjToClause\ \{Jim_Obj*\ clauseObj\}\ Clause*\ \{\n\ \ \ \ \ \ \ \ int\ nTerms\ =\ Jim_ListLength(interp,\ clauseObj)\;\n\ \ \ \ \ \ \ \ Clause*\ clause\ =\ clauseNew(nTerms)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ termObj\ =\ Jim_ListGetIndex(interp,\ clauseObj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ termLen\;\n\ \ \ \ \ \ \ \ \ \ \ \ const\ char*\ termStr\ =\ Jim_GetString(termObj,\ &termLen)\;\n\ \ \ \ \ \ \ \ \ \ \ \ clause->terms\[i\]\ =\ termNew(termStr,\ termLen)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ clause\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ clauseToJimObj\ \{Clause*\ clause\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ termObjs\[clause->nTerms\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ clause->nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ termObjs\[i\]\ =\ Jim_NewStringObj(interp,\ termPtr(clause->terms\[i\]),\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ termLen(clause->terms\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ termObjs,\ clause->nTerms)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ new\ \{\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieNew()\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ add\ \{Trie*\ trie\ Jim_Obj*\ patternObj\ uint64_t\ value\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieAdd(trie,\ tmalloc,\ tfree,\ pattern,\ value)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ lookup\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\ =\ trieLookup(trie,\ pattern,\ results,\ 50)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultObjs\[resultCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ resultObjs\[i\]\ =\ Jim_NewIntObj(interp,\ results\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ resultObjs,\ resultCount)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ remove_\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\;\n\ \ \ \ \ \ \ \ trie\ =\ (Trie\ *)trieRemove(trie,\ tmalloc,\ tfree,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pattern,\ results,\ 50,\ &resultCount)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\ \ \ \ \ \ \ \ return\ trie\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nset\ trieDotify\ \{\{trieLib\ tclifiedTrie\}\ \{\n\ \ \ \ local\ proc\ idify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ generate\ id-able\ word\ by\ eliminating\ all\ non-alphanumeric\n\ \ \ \ \ \ \ \ regsub\ -all\ \{\\W+\}\ \$word\ \"_\"\n\ \ \ \ \}\n\ \ \ \ local\ proc\ labelify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ shorten\ the\ longest\ lines\n\ \ \ \ \ \ \ \ set\ word\ \[join\ \[lmap\ line\ \[split\ \$word\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$word\]\n\ \ \ \ \}\n\ \ \ \ local\ proc\ subdot\ \{subtrie\}\ \{\n\ \ \ \ \ \ \ \ set\ branches\ \[lassign\ \$subtrie\ ptr\ key\ id\]\n\n\ \ \ \ \ \ \ \ set\ dot\ \[list\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ \\\[label=\\\"\[labelify\ \$key\]\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ branch\ \$branches\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$branch\ eq\ \{\}\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ branchptr\ \[lindex\ \$branch\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ ->\ \$branchptr\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \[subdot\ \$branch\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[join\ \$dot\ \"\\n\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[subdot\ \$tclifiedTrie\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWish\ the\ web\ server\ handles\ route\ \{/trie-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/page.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/web/page.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/page.folk programCode Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...replacedOpts ()when /someone/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/atomicallys.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/new.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/web/new.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/new.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ handler\ \{\n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/log.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/web/log.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/log.folk programCode {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/camera-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...replacedO ()when /someone/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/apriltag-frame.folk programCode When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/report.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/report.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/report.folk programCode {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...replace ()when /someone/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/printed-programs.folk programCode {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/index.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/index.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/index.folk programCode Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/web/camera.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/web/camera.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/web/camera.folk programCode {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /... ()when /someone/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/calibration-board.folk programCode #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ -\ paper\ edge\ to\ top\ margin\n#\n#\ -\ paper\ edge\ to\ bottom\ margin\n#\n#\ -\ paper\ edge\ to\ left\ margin\n#\n#\ -\ tag\ inner\ width,\ to\ account\ for\ scaling.\ (We\ also\ want\ this\ tag\n#\ \ \ inner\ width\ to\ be\ exactly\ the\ same\ as\ the\ tag\ inner\ width\ that\ we\n#\ \ \ use\ on\ every\ printed\ program,\ so\ that\ if\ the\ user\ measures\ the\ tag\n#\ \ \ wrong,\ it\ still\ looks\ OK\ on\ the\ average\ program.)\n#\n#\ Then\ we\ can\ correct\ for\ these\ factors\ in\ all\ future\ prints,\ so\ we\n#\ can\ print\ mm-accurate.\n\n#\ These\ values\ are\ all\ in\ points\ (1/72\ of\ an\ inch).\nset\ marginTop\ 48\;\ set\ marginLeft\ 48\n\nset\ measureTop\ \[/\ \$marginTop\ 2\]\;\ set\ measureLeft\ \[/\ \$marginLeft\ 2\]\nset\ tagInnerSideLength\ 70\n\nWhen\ the\ calibration\ measurements\ are\ /measurements/\ \{\n\ \ \ \ set\ m_tag\ \[string\ trimright\ \[dict\ get\ \$measurements\ tagSideLength\]\ mm\]\n\ \ \ \ set\ m_left\ \[string\ trimright\ \[dict\ get\ \$measurements\ left\]\ mm\]\n\ \ \ \ set\ m_bottom\ \[string\ trimright\ \[dict\ get\ \$measurements\ bottom\]\ mm\]\n\n\ \ \ \ #\ Derive\ a\ PostScript\ CTM\ that\ maps\ calibrated\ space\ (origin\ at\n\ \ \ \ #\ paper\ bottom-left,\ 1\ unit\ =\ 1\ physical\ point\ =\ 25.4/72\ mm)\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coordinate\ space.\n\ \ \ \ #\n\ \ \ \ #\ The\ calibration\ board\ was\ printed\ unmediated,\ so\ its\ PS\ coords\n\ \ \ \ #\ are\ the\ printer's\ raw\ coords.\ \ The\ measurement\ lines\ were\ drawn\n\ \ \ \ #\ at\ PS\ positions\ measureLeft\ and\ measureTop\;\ the\ tag\ inner\ side\n\ \ \ \ #\ was\ tagInnerSideLength\ PS\ points.\ \ From\ the\ physical\ measurements\n\ \ \ \ #\ (in\ mm)\ we\ can\ recover\ the\ printer's\ scale\ and\ origin\ offset.\n\ \ \ \ set\ scale\ \[expr\ \{25.4\ *\ \$tagInnerSideLength\ /\ (72.0\ *\ \$m_tag)\}\]\n\ \ \ \ set\ tx\ \[expr\ \{\$measureLeft\ -\ \$m_left\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\ \ \ \ set\ ty\ \[expr\ \{\$measureTop\ -\ \$m_bottom\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\n\ \ \ \ Claim\ the\ calibrated\ print\ scale\ is\ \$scale\n\ \ \ \ Claim\ the\ calibrated\ print\ translation\ is\ \[list\ \$tx\ \$ty\]\n\}\n\nWhen\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ \{\n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...r ()when /someone/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/load-calibration.folk programCode When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\}\n\nWhen\ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n\}\n\nWhen\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n\}\n\nWhen\ the\ collected\ results\ for\ \{/somebody/\ claims\ the\ default\ program\ geometry\ is\ /geom/\}\ are\ /results/\ \{\n\ \ \ \ set\ defaultGeometry\ \{tagSize\ 30mm\ top\ 28mm\ right\ 28mm\ left\ 157mm\ bottom\ 80mm\}\n\ \ \ \ set\ shouldClaim\ false\n\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\ ||\n\ \ \ \ \ \ \ \ \[llength\ \$results\]\ ==\ 1\ &&\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\ ==\ \$defaultGeometry\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeometry\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...rep ()when /someone/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/calibrate-page.folk programCode When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/model.folk is replaced with /...replacedOpts ()when /someone/ wishes program builtin-programs/calibrate/model.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/model.folk programCode #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\nClaim\ the\ calibration\ model\ library\ is\ \[library\ create\ modelLib\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\n\n\ \ \ \ variable\ ROWS\ 5\n\ \ \ \ variable\ COLS\ 4\n\ \ \ \ proc\ rows\ \{\}\ \{\ variable\ ROWS\;\ return\ \$ROWS\ \}\n\ \ \ \ proc\ cols\ \{\}\ \{\ variable\ COLS\;\ return\ \$COLS\ \}\n\ \ \ \ #\ A\ model\ is\ a\ dictionary\ whose\ keys\ are\ tag\ IDs\ and\ where\ each\n\ \ \ \ #\ value\ is\ a\ dictionary\ with\ keys\ `c`\ and\ `p`\ which\ are\ model\n\ \ \ \ #\ points\ (x,\ y).\n\ \ \ \ proc\ unitModel\ \{\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ set\ UNIT_MODEL\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ \ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ \ \ \ \ set\ pad\ \[expr\ \{\$tagSideLength\ /\ 3\}\]\n\ \ \ \ \ \ \ \ for\ \{set\ row\ 0\}\ \{\$row\ <\ \$ROWS\}\ \{incr\ row\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ col\ 0\}\ \{\$col\ <\ \$COLS\}\ \{incr\ col\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[expr\ \{48600\ +\ \$row*\$COLS\ +\ \$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$row\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ outer\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{\$modelX\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{\$modelY\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ inner\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopLeft\ \[list\ \$modelX\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[list\ \$modelX\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c\ \[scale\ 0.5\ \[add\ \$modelTopLeft\ \$modelBottomRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p\ \[list\ \$modelBottomLeft\ \$modelBottomRight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelTopRight\ \$modelTopLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ UNIT_MODEL\ \$id\ \$modelTag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$UNIT_MODEL\n\ \ \ \ \}\n\ \ \ \ #\ Tags\ with\ isPrintedTag\ will\ get\ projected\ to\ PostScript\ points\n\ \ \ \ #\ and\ printed\;\ tags\ with\ isProjectedTag\ will\ get\ projected\ to\n\ \ \ \ #\ Vulkan\ points\ and\ rendered\ on\ projector.\n\n\ \ \ \ #\ Tag\ operations.\n\ \ \ \ #\ ---------------\n\n\ \ \ \ proc\ isCalibrationTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ return\ \$(\$id\ >=\ 48600\ &&\ \$id\ <\ 48600\ +\ \$ROWS*\$COLS)\n\ \ \ \ \}\n\ \ \ \ proc\ isPrintedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ COLS\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{int(\$idx\ /\ \$COLS)\}\]\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$idx\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$row\ %\ 2\ ==\ 0\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 1)\ :\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 0)\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\ \ \ \ proc\ isProjectedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{!\[isPrintedTag\ \$id\]\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ isVersionTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$idx\ %\ 4\ ==\ 1\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\n\ \ \ \ #\ Model\ operations.\n\ \ \ \ #\ -----------------\n\n\ \ \ \ #\ Takes\ a\ model\ object\ (dictionary\ of\ tag\ ID\ =>\ \{p,\ c\})\ and\n\ \ \ \ #\ rotates\ version\ tags\ according\ to\ version.\n\ \ \ \ proc\ updateModelVersion\ \{model\ version\}\ \{\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ version\ tag.\ Rotate\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$model\ \$id\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rotatedCorners\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 4\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ rotatedCorners\ \[lindex\ \$p\ \[expr\ \{(\$i\ +\ \$version)\ %\ 4\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ model\ \$id\ p\ \$rotatedCorners\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$model\n\ \ \ \ \}\n\ \ \ \ proc\ scaleModel\ \{model\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ c\ \[scale\ \$scale\ \[dict\ get\ \$tag\ c\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ p\ \[scale\ \$scale\ \[dict\ get\ \$tag\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ proc\ countProjectedTags\ \{model\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\}\ \{\ incr\ i\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$i\n\ \ \ \ \}\n\n\ \ \ \ #\ Detected\ tag-list\ operations.\n\ \ \ \ #\ -----------------------------\n\ \ \ \ proc\ filterProjectedTagsInDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ return\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Find\ a\ version\ tag\ that\ the\ camera\ saw\ and\ check\ its\ rotation\ to\n\ \ \ \ #\ figure\ out\ the\ model\ version\ that\ we're\ seeing.\n\ \ \ \ proc\ detectVersionFromDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ local\ proc\ getTagAngle\ \{tag\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{atan2(-1\ *\ (\[lindex\ \$p\ 1\ 1\]\ -\ \[lindex\ \$p\ 0\ 1\]),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$p\ 1\ 0\]\ -\ \[lindex\ \$p\ 0\ 0\])\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Find\ any\ version\ tag.\ If\ none\ were\ detected,\ then\ abort\n\ \ \ \ \ \ \ \ #\ and\ wait\ until\ a\ later\ frame.\n\ \ \ \ \ \ \ \ foreach\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isVersionTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagId\ \$tag(id)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagAngle\ \[getTagAngle\ \$tag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ versionTagId\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ #\ Compare\ angle\ to\ angle\ of\ any\ other\ projected\ tag.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$detectedTags\]\ <\ 2\}\ \{\ return\ \{\}\ \}\n\ \ \ \ \ \ \ \ foreach\ detectedTag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$detectedTag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\ &&\ !\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ otherTagAngle\ \[getTagAngle\ \$detectedTag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ otherTagAngle\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ set\ versionAngle\ \[expr\ \{\$versionTagAngle\ -\ \$otherTagAngle\}\]\n\ \ \ \ \ \ \ \ #\ Rotations\ corresponding\ to\ versions\ 0,\ 1,\ 2,\ 3:\n\ \ \ \ \ \ \ \ set\ possibleVersions\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ 1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ 1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ -1\]\n\ \ \ \ \ \ \ \ #\ Which\ of\ the\ possibleVersions\ is\ versionAngle\ closest\ to?\n\ \ \ \ \ \ \ \ return\ \[lindex\ \[lsort-indices\ \[lmap\ \{x\ y\}\ \$possibleVersions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{sqrt((\$x\ -\ cos(\$versionAngle))**2\ +\ (\$y\ -\ sin(\$versionAngle))**2)\}\n\ \ \ \ \ \ \ \ \}\]\]\ 0\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ meanTagsDifference\ \{tags1\ tags2\}\ \{\n\ \ \ \ \ \ \ \ set\ diffsum\ 0.0\n\ \ \ \ \ \ \ \ set\ ndiffs\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$tags1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ cheat\ and\ only\ count\ printed\ tags\ so\ we\ don't\ have\ to\n\ \ \ \ \ \ \ \ \ \ \ \ #\ deal\ with\ versioning.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$tags2\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x1\ y1\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tags2\ \$id\ c\]\ x2\ y2\n\ \ \ \ \ \ \ \ \ \ \ \ set\ diffsum\ \[expr\ \{\$diffsum\ +\ sqrt((\$x1\ -\ \$x2)*(\$x1\ -\ \$x2)\ +\ (\$y1\ -\ \$y2)*(\$y1\ -\ \$y2))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ ndiffs\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$ndiffs\ ==\ 0\}\ \{\ return\ Inf\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$diffsum\ /\ \$ndiffs\}\]\n\ \ \ \ \}\n\}\]\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...replace ()when /someone/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/draw-model.folk programCode When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ calibration\ model\ /model/\ \\\n\ \ \ \ \ \ \ \ using\ model-to-display\ homography\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ with\ message\ /calibrationMessage/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/refine.folk programCode #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (or\n#\ \ \ \ \ projector\ calibration,\ equivalently)\ (see\ Zhengyou\ Zhang)\ using\n#\ \ \ \ \ cmpfit.\n#\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/enumerate.folk programCode {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
$cc proc enumerateDisplays {} Jim_Obj* {
FOLK_ENSURE(volkInitialize() == VK_SUCCESS);
// Create a minimal Vulkan instance for display enumeration.
VkInstance instance;
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* enabledExtensions[] = {
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#ifdef __APPLE__
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
createInfo.ppEnabledExtensionNames = enabledExtensions;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
if (res == VK_ERROR_EXTENSION_NOT_PRESENT) {
FOLK_ERROR("Unable to enumerate displays (for example, this doesn't work on macOS)");
}
FOLK_ERROR("Failed to create Vulkan instance: %d", res);
}
}
volkLoadInstance(instance);
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
vkDestroyInstance(instance, NULL);
return Jim_NewListObj(interp, NULL, 0);
}
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
Jim_Obj *allDisplaysList = Jim_NewListObj(interp, NULL, 0);
// Enumerate displays for each physical device
for (uint32_t devIdx = 0; devIdx < physicalDeviceCount; devIdx++) {
VkPhysicalDevice physicalDevice = physicalDevices[devIdx];
uint32_t displayCount;
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, NULL);
VkDisplayPropertiesKHR displayProps[displayCount];
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProps);
for (uint32_t i = 0; i < displayCount; i++) {
uint32_t modeCount;
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, NULL);
VkDisplayModePropertiesKHR modeProps[modeCount];
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, modeProps);
Jim_Obj *modesList = Jim_NewListObj(interp, NULL, 0);
for (uint32_t j = 0; j < modeCount; j++) {
Jim_Obj *modeDict = Jim_ObjPrintf("visibleRegion {%u %u} refreshRate %u",
modeProps[j].parameters.visibleRegion.width,
modeProps[j].parameters.visibleRegion.height,
modeProps[j].parameters.refreshRate);
Jim_ListAppendElement(interp, modesList, modeDict);
}
int modesLen;
const char *modesStr = Jim_GetString(modesList, &modesLen);
Jim_Obj *displayDict = Jim_ObjPrintf("name {%s} physicalDimensions {%u %u} "
"physicalResolution {%u %u} modes {%s}",
displayProps[i].displayName ? displayProps[i].displayName : "",
displayProps[i].physicalDimensions.width,
displayProps[i].physicalDimensions.height,
displayProps[i].physicalResolution.width,
displayProps[i].physicalResolution.height,
modesStr);
Jim_ListAppendElement(interp, allDisplaysList, displayDict);
}
}
vkDestroyInstance(instance, NULL);
return allDisplaysList;
}
set displayLib [$cc compile]
if {![catch {exec pkg-config --exists glfw3}]} {
Claim $::thisNode has display glfw with info {name "GLFW (windowed)"}
}
try {
foreach display [$displayLib enumerateDisplays] {
Claim $::thisNode has display $display(name) with info $display
}
} finally {
Claim $::thisNode has had displays enumerated
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/matlib.folk programCode When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...replaced ()when /someone/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/calibrate/calibrate.folk programCode #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ calibration\n#\ \ \ \ \ pattern\ PDF,\ have\ the\ user\ measure\ its\ real-world\ dimension,\ run\n#\ \ \ \ \ iterative\ projector-camera\ process\ to\ get\ various\ poses\ of\ the\n#\ \ \ \ \ printed\ tags\ alongside\ projected\ tags,\ do\ linear\ fit\ and\ then\n#\ \ \ \ \ nonlinear\ refinement\ to\ find\ intrinsic\ and\ extrinsic\ parameters\n#\ \ \ \ \ for\ the\ camera\ and\ projector.\n#\n#\ \ \ \ \ Closely\ based\ on\ the\ technique\ in\ Audet\ (2009):\n#\ \ \ \ \ http://www.ok.sc.e.titech.ac.jp/res/PCS/publications/procams2009.pdf\n#\n\npackage\ require\ linalg\n\nforeach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\}\ \{\n\ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\}\n\nHold!\ -key\ \{calibration\ poses\ max\}\ \\\n\ \ \ \ Claim\ the\ calibration\ poses\ max\ is\ 10\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ AprilTag\ detector\ maker\ is\ /makeAprilTagDetector/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ calibrate\ camera\ /camera/\ to\ display\ /display/\ \\\n\ \ \ \ \ \ \ \ \ using\ measurements\ /measurements/\ \{\n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nfn\ processHomography\ \{H\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n\}\n\n\n#\ Uses\ Zhang's\ calibration\ technique\n#\ (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf)\n#\ to\ calibrate\ a\ projector\ or\ camera\ given\ a\ known\ 2D\ planar\ pattern\n#\ and\ multiple\ observed\ poses.\n#\n#\ Returns\ intrinsic\ matrix\ for\ the\ camera/projector,\ which\ explains\n#\ how\ 3D\ real-world\ coordinates\ get\ projected\ to\ 2D\ coordinates\ by\n#\ that\ device.\ (The\ intrinsic\ matrix\ can\ be\ used\ with\ an\ AprilTag\n#\ detector\ to\ get\ real-world\ coordinates\ for\ each\ AprilTag.)\n#\n#\ Arguments:\n#\ \ \ \ \ \ \ \ \ width\ \ width\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ height\ height\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ Hs\ \ \ \ \ a\ list\ of\ N\ homographies\ from\ camera/projector\ image\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ plane\ ->\ model\ plane\ (for\ N\ different\ poses).\nfn\ zhangUnrefinedCalibrate\ \{name\ width\ height\ Hs\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n\}\n\nfn\ setCameraToProjectorExtrinsics\ \{modelLib\ calibrationVar\ calibrationPoses\}\ \{\n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n\}\n\n#\ End-to-end\ calibrates\ a\ camera-projector\ pair.\ calibrationPoses\ is\n#\ a\ list\ of\ N\ pose\ dictionaries.\ Each\ pose\ dictionary\ includes\ `tags`\n#\ from\ a\ camera\ detection,\ `model`\ with\ coordinates\ in\ meters,\n#\ `H_modelToDisplay`.\nfn\ unrefinedCalibrateCameraAndProjector\ \{modelLib\ matLib\ calibrationPoses\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n\}\n\nWhen\ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ &\\\n\ \ \ \ \ the\ calibration\ refiner\ is\ /refineCalibration/\ \{\n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/pipelines.folk programCode #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ compilation.\n#\ \ \ \ \ Created\ once\ (not\ per-display).\ Pipelines\ use\ dynamic\ viewport/scissor\n#\ \ \ \ \ so\ they\ work\ across\ displays\ of\ different\ sizes.\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/gpu.folk programCode {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq "darwin"} {
# We hard-code gpu.folk into thread 0, so we should abort if not
# running that way.
return
}
fn defineVulkanHandleType {cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
}
Claim the GPU Vulkan handle type definer is [fn defineVulkanHandleType]
fn gpuInit {useGlfw} {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
}
if {$::tcl_platform(os) eq "darwin"} {
gpuInit true
return
}
When $::thisNode has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/textures.folk is replaced with /...replacedOpts/ \ ()when /someone/ wishes program builtin-programs/gpu/textures.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/textures.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/draw.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/gpu/draw.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/draw.folk programCode #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ and\n#\ \ \ \ \ numerical\ parameters\ (so\ you\ can\ draw\ images,\ shapes,\ etc.)\n#\ \ \ \ \ Single\ render\ thread\ handles\ all\ displays.\n\nif\ \{\[info\ exists\ this\]\ &&\ \$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ #\ We\ hard-code\ draw.folk\ into\ thread\ 0,\ so\ we\ should\ abort\ if\ not\n\ \ \ \ #\ running\ that\ way.\n\ \ \ \ return\n\}\n\nWhen\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ compiler\ library\ is\ /pipelineCompilerLib/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/toy-shader.folk programCode #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <openssl/sha.h>\n\$cc\ proc\ sha1\ \{char*\ d\}\ Jim_Obj*\ \{\n\ \ \ \ unsigned\ char\ md\[20\]\;\n\ \ \ \ SHA1((unsigned\ char\ *)d,\ strlen(d),\ md)\;\n\ \ \ \ return\ Jim_NewStringObj(interp,\ (char\ *)md,\ 20)\;\n\}\n\$cc\ endcflags\ -lssl\ -lcrypto\nset\ sha1Lib\ \[\$cc\ compile\]\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ \{\n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...replacedOpts/ \ ()when /someone/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/canvases.folk programCode When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/vma.folk is replaced with /...replacedOpts/ \n\ \ ()when /someone/ wishes program builtin-programs/gpu/vma.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/vma.folk programCode When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/camera/rpi.folk is replaced with /...replacedOpts/ \n\ ()when /someone/ wishes program builtin-programs/camera/rpi.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/camera/rpi.folk programCode #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ error\ \"Raspberry\ Pi\ camera\ driver\ only\ runs\ on\ Linux.\"\n\}\n\nset\ makeCamera\ \{\n\ \ \ \ set\ cpp\ \[C++\]\n\ \ \ \ \$cpp\ extend\ \$imageLib\n\ \ \ \ \$cpp\ include\ <iostream>\n\ \ \ \ \$cpp\ include\ <iomanip>\n\ \ \ \ \$cpp\ include\ <mutex>\n\ \ \ \ \$cpp\ include\ <condition_variable>\n\ \ \ \ \$cpp\ include\ <queue>\n\ \ \ \ \$cpp\ include\ <sys/mman.h>\n\n\ \ \ \ \$cpp\ include\ <libcamera/libcamera.h>\n\ \ \ \ #\ osnr:\ HACK:\ just\ throwing\ any\ possible\ path\ in.\n\ \ \ \ \$cpp\ cflags\ -I/usr/local/include/libcamera\ -I/usr/include/libcamera\n\ \ \ \ \$cpp\ endcflags\ -lcamera\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ using\ namespace\ libcamera\;\n\n\ \ \ \ \ \ \ \ std::unique_ptr<CameraManager>\ cm\;\n\ \ \ \ \ \ \ \ std::shared_ptr<Camera>\ camera\;\n\tstd::unique_ptr<CameraConfiguration>\ config\;\n\tFrameBufferAllocator\ *allocator\;\n\n\ \ \ \ \ \ \ \ //\ This\ vector\ always\ owns\ all\ the\ request\ objects.\n\tstd::vector<std::unique_ptr<Request>>\ requests\;\n\n\ \ \ \ \ \ \ \ std::mutex\ completedRequestsMutex\;\n\ \ \ \ \ \ \ \ std::queue<Request\ *>\ completedRequests\;\n\ \ \ \ \ \ \ \ std::condition_variable\ completedRequestsCv\;\n\n\ \ \ \ \ \ \ \ uint32_t\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ frameHeight\;\n\ \ \ \ \ \ \ \ uint32_t\ frameBytesPerRow\;\n\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ cameraOpen\ \{char*\ id\ int\ width\ int\ height\}\ void\ \{\n\ \ \ \ \ \ \ \ cm\ =\ std::make_unique<CameraManager>()\;\n\ \ \ \ \ \ \ \ cm->start()\;\n\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ cameras:\"\ <<\ std::endl\;\n\tfor\ (auto\ const\ &camera\ :\ cm->cameras())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"\ -\ \"\ <<\ camera->id()\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ camera\ =\ cm->get(id)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(camera\ !=\ nullptr)\;\n\ \ \ \ \ \ \ \ camera->acquire()\;\n\n\ \ \ \ \ \ \ \ config\ =\ camera->generateConfiguration(\{\ StreamRole::Viewfinder\ \})\;\n\ \ \ \ \ \ \ \ StreamConfiguration\ &streamConfig\ =\ config->at(0)\;\n\ \ \ \ \ \ \ \ streamConfig.size\ =\ Size(width,\ height)\;\n\ \ \ \ \ \ \ \ streamConfig.pixelFormat\ =\ PixelFormat::fromString(\"YUV420\")\;\n\n\ \ \ \ \ \ \ \ config->validate()\;\n\ \ \ \ \ \ \ \ frameWidth\ =\ streamConfig.size.width\;\n\ \ \ \ \ \ \ \ frameHeight\ =\ streamConfig.size.height\;\n\ \ \ \ \ \ \ \ frameBytesPerRow\ =\ streamConfig.stride\;\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"frameWidth:\ \"\ <<\ frameWidth\ <<\ \"\ frameHeight:\ \"\ <<\ frameHeight\ <<\ std::endl\;\n\n\tcamera->configure(config.get())\;\n\n\ \ \ \ \ \ \ \ allocator\ =\ new\ FrameBufferAllocator(camera)\;\n\tfor\ (StreamConfiguration\ &cfg\ :\ *config)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ allocator->allocate(cfg.stream())\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Can't\ allocate\ buffers\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ allocated\ =\ allocator->buffers(cfg.stream()).size()\;\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ Allocated\ \"\ <<\ allocated\ <<\ \"\ buffers\ for\ stream\"\ <<\ std::endl\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (PixelFormat\ &format\ :\ cfg.formats().pixelformats())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ std::cout\ <<\ \"camera/rpi:\ Stream\ supports\ format\ \"\ <<\ format\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (Size\ &size\ :\ cfg.formats().sizes(format))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ \ \ std::cout\ <<\ \"\ \ ->\ supports\ size\ \"\ <<\ size\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\t\}\n\n\ \ \ \ \ \ \ \ Stream\ *stream\ =\ streamConfig.stream()\;\n\ \ \ \ \ \ \ \ assert(streamConfig.pixelFormat.toString()\ ==\ \"YUV420\")\;\n\n\ \ \ \ \ \ \ \ const\ std::vector<std::unique_ptr<FrameBuffer>>\ &buffers\ =\ allocator->buffers(stream)\;\n\tfor\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ buffers.size()\;\ ++i)\ \{\n\t\tstd::unique_ptr<Request>\ request\ =\ camera->createRequest()\;\n\t\tif\ (!request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ create\ request\")\;\n\t\t\}\n\n\t\tconst\ std::unique_ptr<FrameBuffer>\ &buffer\ =\ buffers\[i\]\;\n\t\tint\ ret\ =\ request->addBuffer(stream,\ buffer.get())\;\n\t\tif\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ set\ buffer\ for\ request\")\;\n\t\t\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ControlList\ &controls\ =\ request->controls()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AeEnable,\ false)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::ExposureTime,\ 35000)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AfMode,\ controls::AfModeManual)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Focus\ 30cm\ away\ (0.3m\ ->\ 1/0.3\ =\ 3.3).\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::LensPosition,\ 1.6)\;\n\n\t\trequests.push_back(std::move(request))\;\n\t\}\n\n\tcamera->requestCompleted.connect(requestComplete)\;\n\n\ \ \ \ \ \ \ \ camera->start()\;\n\tfor\ (std::unique_ptr<Request>\ &request\ :\ requests)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(request.get())\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (request->status()\ ==\ Request::RequestCancelled)\ \{\n\t\treturn\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.lock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.push(request)\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.unlock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsCv.notify_one()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ static\ void\ processRequestAndCopyFrame(Request\ *request,\ Image\ im)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ Request::BufferMap\ &buffers\ =\ request->buffers()\;\n\ \ \ \ \ \ \ \ \ \ \ \ assert(buffers.size()\ ==\ 1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (auto\ bufferPair\ :\ buffers)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ (Unused)\ Stream\ *stream\ =\ bufferPair.first\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FrameBuffer\ *buffer\ =\ bufferPair.second\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ FrameMetadata\ &metadata\ =\ buffer->metadata()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(metadata.planes().size()\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(buffer->planes().size()\ ==\ 3)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto\ &plane\ =\ buffer->planes()\[0\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ fd\ =\ plane.fd.get()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *addr\ =\ mmap64(NULL,\ plane.length,\ PROT_READ,\ MAP_PRIVATE,\ fd,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (addr\ ==\ MAP_FAILED)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ MAP_FAILED\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *planeData\ =\ (uint8_t\ *)addr\ +\ plane.offset\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(im.data,\ planeData,\ frameHeight\ *\ frameBytesPerRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ munmap(addr,\ plane.length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ newImage\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ uint32_t\ width\ =\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ height\ =\ frameHeight\;\n\ \ \ \ \ \ \ \ int\ components\ =\ 1\;\n\ \ \ \ \ \ \ \ uint8_t\ *data\ =\ (uint8_t\ *)\ malloc(width*components*height)\;\n\ \ \ \ \ \ \ \ return\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ components,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ width*components,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ freeImage\ \{Image\ image\}\ void\ \{\n\ \ \ \ \ \ \ \ free(image.data)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ grayFrame\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ Request\ *latestRequest\ =\ nullptr\;\n\n\ \ \ \ \ \ \ \ //\ We\ want\ to\ drain\ the\ queue\ of\ completed\ requests.\n\ \ \ \ \ \ \ \ std::unique_lock\ lk(completedRequestsMutex)\;\n\ \ \ \ \ \ \ \ completedRequestsCv.wait(lk,\ \[\]\{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ !completedRequests.empty()\;\n\ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ while\ (!completedRequests.empty())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (latestRequest\ !=\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ We're\ skipping\ this\ request,\ because\ we\ have\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ newer\ one\ in\ the\ queue.\ Requeue\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ latestRequest\ =\ completedRequests.front()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.pop()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lk.unlock()\;\n\n\ \ \ \ \ \ \ \ if\ (latestRequest\ ==\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"No\ new\ frame\ yet\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ newImage()\;\n\ \ \ \ \ \ \ \ processRequestAndCopyFrame(latestRequest,\ im)\;\n\n\ \ \ \ \ \ \ \ /*\ Re-queue\ the\ Request\ to\ the\ camera.\ */\n\ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ compile\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /cameraPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/decorations/label.folk is replaced with /...replacedOp ()when /someone/ wishes program builtin-programs/decorations/label.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/decorations/label.folk programCode {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
}
When /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/decorations/outline.folk is replaced with /...replaced ()when /someone/ wishes program builtin-programs/decorations/outline.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/decorations/outline.folk programCode When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...replacedO ()when /someone/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/editor/draw-editor.folk programCode When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...replaced ()when /someone/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/editor/editor-utils.folk programCode {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport {originalText x y width height} {
set lines [split $originalText \n]
set lines [lrange $lines $y [expr {($height - 1) + $y}]]
set lines [lmap line $lines {
set line [string range $line $x [expr {($width - 1) + $x}]]
}]
return [join $lines \n]
}
proc cursorToXy {code cursor} {
set codeBeforeCursor [string range $code 0 [- $cursor 1]]
set linesBeforeCursor [split $codeBeforeCursor "\n"]
set lineCountBeforeCursor [llength $linesBeforeCursor]
set cursorX [string length [lindex $linesBeforeCursor end]]
set cursorY [max [- $lineCountBeforeCursor 1] 0]
return [list $cursorX $cursorY]
}
proc xyToCursor {code cursorX cursorY} {
if { $cursorX < 0 } { set cursorX 0 }
if { $cursorY < 0 } { set cursorY 0 }
set lines [split $code "\n"]
set maxCursorY [max 0 [- [llength $lines] 1]]
set cursorY [min $cursorY $maxCursorY]
set relevantLines [lrange $lines 0 [- $cursorY 1]]
set relevantLineLen [string length [lindex $lines $cursorY]]
set joined [join $relevantLines "\n"]
# make sure cursorX < line length
set cursorX [min $cursorX $relevantLineLen]
set cursor [+ [string length $joined] $cursorX]
# don't forget to add the length of \n at the beginning
if {$cursorY > 0} { incr cursor }
return $cursor
}
proc insertText {code cursor newText} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code $cursor end]
set joined [join [list $before $newText $after] ""]
incr cursor
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $joined $cursor $maxCursorX]
}
proc deleteText {code cursor count} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code [+ $cursor $count] end]
set joined [join [list $before $after] ""]
return $joined
}
proc deleteToBeginning {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
set newLine [string range $line $x end]
lset lines $y $newLine
return [join $lines "\n"]
}
proc getLine {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
}
proc getLineLength {code cursor} {
set line [getLine $code $cursor]
set ll [string length $line]
return $ll
}
# returns {newCursor newMaxCursorX}
proc handleNavigation {key code cursor maxCursorX} {
switch $key {
Left {
set cursor [- $cursor 1]
set cursor [max $cursor 0]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Right {
set cursor [+ $cursor 1]
set codeLength [string length $code]
set cursor [min $cursor $codeLength]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Up {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [- $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Down {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [+ $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Control_a {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX 0
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
Control_e {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX [getLineLength $code $cursor]
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
}
return [list $cursor $maxCursorX]
}
# returns {newCode newCursor newMaxCursorX}
proc handleRemovalAndReturn {key code cursor maxCursorX} {
switch $key {
Delete {
if { $cursor != 0 } {
set cursor [- $cursor 1]
set code [deleteText $code $cursor 1]
set maxCursorX [lindex [cursorToXy $code $cursor] 0]
}
}
Remove {
set code [deleteText $code $cursor 1]
}
Control_u {
# delete from cursor back to 0 and move cursor to 0
lassign [cursorToXy $code $cursor] cursorX cursorY
set code [deleteToBeginning $code $cursor]
set newX 0
set cursor [xyToCursor $code $newX $cursorY]
}
Return {
# figure out how many spaces there are before the current line
regexp {^(\s*)} [getLine $code $cursor] -> spacing
set spacingLen [string length $spacing]
lassign [insertText $code $cursor "\n$spacing"] code
set maxCursorX $spacingLen
set cursor [+ $cursor [+ 1 $spacingLen]]
}
}
return [list $code $cursor $maxCursorX]
}
proc getSelectedText {code selAnchor cursor} {
set start [min $selAnchor $cursor]
set end [max $selAnchor $cursor]
return [string range $code $start [- $end 1]]
}
proc replaceRange {code rangeStart rangeEnd newText} {
if {$rangeStart > 0} {
set before [string range $code 0 [- $rangeStart 1]]
} else {
set before ""
}
set after [string range $code $rangeEnd end]
set code "${before}${newText}${after}"
set cursor [+ $rangeStart [string length $newText]]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $code $cursor $maxCursorX]
}
proc lineNumberView {ystart linecount} {
set yend [expr {$ystart + $linecount}]
set numbers [list]
for {set i [expr {$ystart + 1}]} {$i <= $yend} {incr i} {
lappend numbers $i
}
join $numbers "\n"
}
# For rendering:
proc getAdvance {em} {
# From NeomatrixCode.csv
return $(0.5859375 * $em)
}
proc widthAndHeight {resolvedGeom} {
set tagSize [dict get $resolvedGeom tagSize]
set left [dict get $resolvedGeom left]
set right [dict get $resolvedGeom right]
set top [dict get $resolvedGeom top]
set bottom [dict get $resolvedGeom bottom]
set width $($left + $tagSize + $right)
set height $($top + $tagSize + $bottom)
return [list $width $height]
}
# given program and the editor options, figure out how many characters can
# fit in this editor
proc editorSizeInCharacters {margin resolvedGeom options} {
set textScale [dict get $options scale]
set advance [getAdvance $textScale]
lassign [widthAndHeight $resolvedGeom] width height
set width $($width - [lindex $margin 3] - $advance*2.5 - [lindex $margin 1])
set height $($height - [lindex $margin 0] - [lindex $margin 2])
set widthInCharacters $(int($width / $advance))
set heightInCharacters $(int($height / $textScale))
return [list $widthInCharacters $heightInCharacters]
}
}]
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/editor/editor.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/editor/editor.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/editor/editor.folk programCode #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ later,\ or\ exclude\ keyboards\ that\ opt\ out.\nWhen\ /k/\ is\ a\ keyboard\ with\ /...opts/\ \{\n\ \ \ \ Wish\ tag\ \$k\ is\ stabilized\n\n\ \ \ \ When\ \$k\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ claims\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Create\ a\ synthetic\ editor\ on\ top\ of\ the\ program\ being\ edited,.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editor\ \[list\ \$k\ editor\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ is\ an\ editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ has\ a\ canvas\ with\ layer\ 98\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ has\ resolved\ geometry\ \$geom\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ quad\ /q/\ \{\ Claim\ \$editor\ has\ quad\ \$q\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ has\ created\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$editor\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$program\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ program\ save\ directory\ is\ /programDir/\ &\\\n\ \ \ \ \ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...replaced ()when /someone/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/editor/print-editor.folk programCode fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\}\n\nSubscribe:\ print\ program\ from\ editor\ /editor/\ \{\n\ \ \ \ set\ options\ \[editorToPrintOptions\ \$editor\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\n\n#\ Print\ preview:\nWhen\ the\ codeToPostScript\ is\ /codeToPostScript/\ &\\\n\ \ \ \ \ /someone/\ wishes\ editor\ /editor/\ has\ a\ print\ preview\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...replace ()when /someone/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/saving/save-programs.folk programCode When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/saving/saving.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/saving/saving.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/saving/saving.folk programCode set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\]\}\ \{\n\ \ \ \ file\ mkdir\ \$dataDirectory\n\}\n\n#\ make\ sure\ the\ migration\ happens\ before\ loading\ everything,\n#\ so\ we\ load\ in\ the\ migrated\ data\nWhen\ the\ migration\ is\ complete\ \{\n\ \ \ \ set\ namespaces\ \[glob\ -nocomplain\ \$dataDirectory/*/\]\n\n\ \ \ \ foreach\ namespace\ \$namespaces\ \{\n\ \ \ \ \ \ \ \ set\ namespaceName\ \[file\ tail\ \$namespace\]\n\ \ \ \ \ \ \ \ Wish\ to\ deserialize\ namespace\ \$namespaceName\ with\ directory\ \$namespace\n\ \ \ \ \}\n\}\n\nWhen\ when\ the\ /fileType/\ save\ directory\ is\ /anything/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ set\ serdeDirectory\ \"\$dataDirectory/\$fileType\"\n\n\ \ \ \ #\ make\ sure\ directory\ exists\n\ \ \ \ file\ mkdir\ \$serdeDirectory\n\n\ \ \ \ Claim\ the\ \$fileType\ save\ directory\ is\ \$serdeDirectory\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/saving/migrate.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/saving/migrate.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/saving/migrate.folk programCode When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /programDirectory/\ &\\\n\ \ \ \ \ saving\ is\ ready\ \{\n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...replacedOp ()when /someone/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/saving/save-holds.folk programCode set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ \"jim.h\"\n\n\$cc\ code\ \{\n\n/*\ Generic\ string\ hash\ function\ from\ jim.c\ */\nstatic\ unsigned\ int\ cacheGenHashFunction(const\ unsigned\ char\ *string,\ int\ length)\ \{\n\ \ \ \ unsigned\ result\ =\ 0\;\n\ \ \ \ string\ +=\ length\;\n\ \ \ \ while\ (length--)\ \{\n\ \ \ \ \ \ \ \ result\ +=\ (result\ <<\ 3)\ +\ (unsigned\ char)(*--string)\;\n\ \ \ \ \}\n\ \ \ \ return\ result\;\n\}\nstatic\ unsigned\ int\ holdHTHashFunction(const\ void\ *key)\ \{\n\ \ \ \ return\ cacheGenHashFunction(key,\ strlen(key))\;\n\}\nstatic\ void\ *holdHTKeyDup(void\ *privdata,\ const\ void\ *key)\ \{\n\ \ \ \ return\ strdup(key)\;\n\}\nstatic\ void\ *holdHTValDup(void\ *privdata,\ const\ void\ *val)\ \{\n\ \ \ \ return\ strdup(val)\;\n\}\nstatic\ int\ holdHTKeyCompare(void\ *privdata,\ const\ void\ *key1,\ const\ void\ *key2)\ \{\n\ \ \ \ return\ strcmp(key1,\ key2)\ ==\ 0\;\n\}\nstatic\ void\ holdHTKeyDestructor(void\ *privdata,\ void\ *key)\ \{\n\ \ \ \ free(key)\;\n\}\nstatic\ void\ holdHTValDestructor(void\ *privdata,\ void\ *val)\ \{\n\ \ \ \ free(val)\;\n\}\n\nstatic\ const\ Jim_HashTableType\ holdHashTableType\ =\ \{\n\ \ \ \ .hashFunction\ =\ holdHTHashFunction,\n\ \ \ \ .keyDup\ =\ holdHTKeyDup,\n\ \ \ \ .valDup\ =\ holdHTValDup,\n\ \ \ \ .keyCompare\ =\ holdHTKeyCompare,\n\ \ \ \ .keyDestructor\ =\ holdHTKeyDestructor,\n\ \ \ \ .valDestructor\ =\ holdHTValDestructor\n\}\;\n\n//\ key\ =\ value\ of\ -on\ passed\ to\ Hold!,\n//\ val\ =\ string\ that\ can\ be\ converted\ to\ a\ jim\ dict,\ with\n//\ that\ dict\ having\ its\ key\ =\ the\ value\ passed\ to\ -key\n//\ and\ its\ value\ =\ its\ corresponding\ held\ statement\nstatic\ Jim_HashTable\ holds\;\nstatic\ int\ areHoldsInitialized\ =\ 0\;\n\nstatic\ pthread_mutex_t\ holdMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ if\ (!areHoldsInitialized)\ \{\n\ \ \ \ \ \ \ \ areHoldsInitialized\ =\ 1\;\n\ \ \ \ \ \ \ \ Jim_InitHashTable(&holds,\ &holdHashTableType,\ interp)\;\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n\$cc\ proc\ loadHolds\ \{char*\ canonicalName\ char*\ holdStr\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonicalName,\ (void\ *)holdStr)\;\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n#\ canonical,\ tclEscaped,\ and\ filename\ all\ have\ to\ do\ with\ the\ value\ from\ -on\ in\ Hold!\n\$cc\ proc\ saveHold\ \{char*\ canonical\ Jim_Obj*\ tclEscaped\ char*\ filename\ Jim_Obj*\ key\ Jim_Obj*\ clause\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ assert(areHoldsInitialized)\;\n\n\ \ \ \ Jim_Obj*\ holdDict\ =\ NULL\;\n\n\ \ \ \ Jim_HashEntry*\ he\ =\ Jim_FindHashEntry(&holds,\ canonical)\;\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ //\ this\ is\ this\ files'\ first\ hold\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewStringObj(interp,\ (char\ *)Jim_GetHashEntryVal(he),\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ empty\ clause,\ e.g.\ removal\n\ \ \ \ if\ (Jim_Length(clause)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ NULL)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ clause)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonical,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_SetHashVal(&holds,\ he,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\n\ \ \ \ //\ grab\ entries\ from\ dict\n\ \ \ \ int\ dictLen\ =\ 0\;\n\ \ \ \ Jim_Obj**\ dictValues\ =\ Jim_DictPairs(interp,\ holdDict,\ &dictLen)\;\n\n\ \ \ \ if\ (dictLen\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ //\ write\ changes\n\ \ \ \ \ \ \ \ FILE*\ file\ =\ fopen(filename,\ \"w+b\")\;\n\ \ \ \ \ \ \ \ assert(file\ !=\ NULL)\;\n\n\ \ \ \ \ \ \ \ //\ write\ the\ filename\ in\ tcl\ form\ at\ the\ top\ of\ the\ file\n\ \ \ \ \ \ \ \ fwrite(Jim_String(tclEscaped),\ 1,\ Jim_Length(tclEscaped),\ file)\;\n\ \ \ \ \ \ \ \ fwrite(\"\\n\\n\",\ 1,\ 2,\ file)\;\n\n\ \ \ \ \ \ \ \ //\ write\ all\ hash\ entries,\ with\ one\ entry\ per\ line\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ dictLen\;\ i\ +=\ 2)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ pair\[\]\ =\ \{\ dictValues\[i\],\ dictValues\[i\ +\ 1\]\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ tmpListObj\ =\ Jim_NewListObj(interp,\ pair,\ 2)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(Jim_String(tmpListObj),\ 1,\ Jim_Length(tmpListObj),\ file)\;\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(\"\\n\",\ 1,\ 1,\ file)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_FreeNewObj(interp,\ tmpListObj)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ fclose(file)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ //\ the\ dict\ is\ empty,\ so\ we\ should\ delete\ its\ hold\ file\ if\ it\ exists\n\ \ \ \ \ \ \ \ remove(filename)\;\ //\ no\ need\ to\ check\ error\n\ \ \ \ \}\n\n\ \ \ \ Jim_FreeNewObj(interp,\ holdDict)\;\n\}\n\nset\ savedHoldsLib\ \[\$cc\ compile\]\n\$savedHoldsLib\ init\n\nWhen\ /someone/\ wishes\ to\ deserialize\ namespace\ hold\ with\ directory\ /directory/\ \{\n\ \ \ \ set\ holdFiles\ \[glob\ -nocomplain\ \$directory/*\]\n\n\ \ \ \ foreach\ holdFile\ \$holdFiles\ \{\n\ \ \ \ \ \ \ \ set\ fd\ \[open\ \$holdFile\ r\]\n\ \ \ \ \ \ \ \ set\ holds\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ #\ the\ hold\ file's\ first\ line\ is\ its\ canonical\ name\ (since\n\ \ \ \ \ \ \ \ #\ having\ /\ in\ a\ filename\ would\ mess\ a\ lot\ of\ stuff\ up),\n\ \ \ \ \ \ \ \ #\ while\ the\ rest\ of\ the\ file\ is\ a\ dict\ of\ holds\n\ \ \ \ \ \ \ \ set\ canonicalName\ \[lindex\ \$holds\ 0\]\n\ \ \ \ \ \ \ \ set\ holdDict\ \[lrange\ \$holds\ 1\ end\]\n\n\ \ \ \ \ \ \ \ dict\ for\ \{key\ clause\}\ \$holdDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ \$canonicalName\ -key\ \$key\ --\ \{*\}\$clause\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ loadHolds\ \$canonicalName\ \$holdDict\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ saved\ holds\ are\ loaded\n\}\n\nWhen\ the\ hold\ save\ directory\ is\ /holdDirectory/\ \{\n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/gpu/gpu-fns.folk programCode {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
Wish the GPU compiles function "wedge2d" {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
# See https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/
Wish the GPU compiles function "invBilinear" {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
}} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/shapes/region.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/shapes/region.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/shapes/region.folk programCode #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ used\ to\ create\ sensitive\ areas\ other\ pages\ can\ collect.\nWhen\ /someone/\ wishes\ /p/\ adds\ region\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ region\ /r/\ has\ highlight\ /highlighted/\ with\ /...options/\ \{\n\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\n\ \ if\ \{\$highlighted\}\ \{\n\ \ \ \ set\ verts\ \[region\ vertices\ \$r\]\n\ \ \ \ set\ edges\ \[region\ edges\ \$r\]\n\ \ \ \ lappend\ verts\ \[lindex\ \$verts\ 0\]\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$verts\ color\ \$color\ width\ \$thickness\ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/display/arc.folk is replaced with /...replacedOpts/ \n ()when /someone/ wishes program builtin-programs/display/arc.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/display/arc.folk programCode #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n#\ \ \ \ \ Wish\ to\ draw\ an\ arc\ with\ x\ \$x\ y\ \$y\ start\ 0\ arclen\ 1\ thickness\ 3\ radius\ 100\ color\ green\n#\ \ \ \}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"arc\"\ \{\{vec2\ center\ float\ start\ float\ arclen\ float\ radius\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\ \ \ \ \ \ \ \ \ center\ +\ r\n\ \ \ \ )\;\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\}\ \{\n\ \ \ \ #define\ M_TWO_PI\ 6.283185307179586\n\ \ \ \ start\ =\ clamp(start,\ 0,\ M_TWO_PI)\;\n\ \ \ \ arclen\ =\ clamp(arclen,\ 0,\ M_TWO_PI)\;\n\n\ \ \ \ float\ dist\ =\ length(gl_FragCoord.xy\ -\ center)\ -\ radius\;\n\ \ \ \ float\ angle\ =\ atan(-(gl_FragCoord.y\ -\ center.y),\ gl_FragCoord.x\ -\ center.x)\;\n\n\ \ \ \ //\ Shift\ angle\ from\ \[-pi,\ pi)\ to\ \[0,\ 2*pi\]\n\ \ \ \ angle\ =\ (angle\ <\ 0)\ ?\ (angle\ +\ M_TWO_PI)\ :\ angle\;\n\ \ \ \ float\ end\ =\ start\ +\ arclen\;\n\n\ \ \ \ return\ ((dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((end\ <\ M_TWO_PI\ &&\ angle\ >\ start\ &&\ angle\ <\ end)\ ||\ \n\ \ \ \ \ \ \ \ \ \ \ \ (end\ >=\ M_TWO_PI\ &&\ (angle\ >\ start\ ||\ angle\ <\ end-M_TWO_PI))))\ ?\ color\ :\ vec4(0,\ 0,\ 0,\ 0)\;\n\n\}\}\n\nWhen\ /someone/\ wishes\ to\ draw\ an\ arc\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/display/curve.folk is replaced with /...replacedOpts/ ()when /someone/ wishes program builtin-programs/display/curve.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/display/curve.folk programCode \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ compiles\ function\ \"bboxBezier\"\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\}\ vec4\ \{\n\ \ \ \ //\ Exact\ BBox\ to\ a\ quadratic\ bezier\n\ \ \ \ //\ extremes\n\ \ \ \ vec2\ mi\ =\ min(p0,p3)\;\n\ \ \ \ vec2\ ma\ =\ max(p0,p3)\;\n\n\ \ \ \ vec2\ k0\ =\ -1.0*p0\ +\ 1.0*p1\;\n\ \ \ \ vec2\ k1\ =\ \ 1.0*p0\ -\ 2.0*p1\ +\ 1.0*p2\;\n\ \ \ \ vec2\ k2\ =\ -1.0*p0\ +\ 3.0*p1\ -\ 3.0*p2\ +\ 1.0*p3\;\n\n\ \ \ \ vec2\ h\ =\ k1*k1\ -\ k0*k2\;\n\n\ \ \ \ if(\ h.x>0.0\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.x\ =\ sqrt(h.x)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.x\ -\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.x/(-k1.x-h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.x\ +\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ t\ =\ k0.x/(-k1.x+h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if(\ h.y>0.0)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.y\ =\ sqrt(h.y)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.y\ -\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.y/(-k1.y-h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.y\ +\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ t\ =\ k0.y/(-k1.y+h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \n\ \ \ \ return\ vec4(\ mi,\ ma\ )\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ sdSegmentSq\ \{\{vec2\ p\ vec2\ a\ vec2\ b\}\ float\ \{\n\ \ \ \ vec2\ pa\ =\ p-a,\ ba\ =\ b-a\;\n\ \ \ \ float\ h\ =\ clamp(\ dot(pa,ba)/dot(ba,ba),\ 0.0,\ 1.0\ )\;\n\ \ \ \ vec2\ d\ =\ pa\ -\ ba*h\;\n\ \ \ \ return\ dot(d,\ d)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ udBezier\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ vec2\ pos\}\ vec2\ \{\n\ \ \ \ const\ int\ kNum\ =\ 50\;\n\ \ \ \ vec2\ res\ =\ vec2(1e10,0.0)\;\n\ \ \ \ vec2\ a\ =\ p0\;\n\ \ \ \ for(\ int\ i=1\;\ i<kNum\;\ i++\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ float\ t\ =\ float(i)/float(kNum-1)\;\n\ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ vec2\ b\ =\ p0*s*s*s\ +\ p1*3.0*s*s*t\ +\ p2*3.0*s*t*t\ +\ p3*t*t*t\;\n\ \ \ \ \ \ \ \ float\ d\ =\ sdSegmentSq(\ pos,\ a,\ b\ )\;\n\ \ \ \ \ \ \ \ if(\ d<res.x\ )\ res\ =\ vec2(d,t)\;\n\ \ \ \ \ \ \ \ a\ =\ b\;\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ vec2(sqrt(res.x),res.y)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"curve\"\ \{\n\ \ \{\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ //\ Need\ to\ calculate\ the\ bounds\ of\ the\ curve\n\ \ \ \ vec2\ from\ =\ min(min(p0,p1),min(p2,p3))\;\n\ \ \ \ vec2\ to\ =\ max(max(p0,p1),max(p2,p3))\;\n\ \ \ \ \n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ min(from,\ to)\ -\ thickness,\n\ \ \ \ \ \ vec2(max(from.x,\ to.x)\ +\ thickness,\ min(from.y,\ to.y)\ -\ thickness),\n\ \ \ \ \ \ vec2(min(from.x,\ to.x)\ -\ thickness,\ max(from.y,\ to.y)\ +\ thickness),\n\ \ \ \ \ \ max(from,\ to)\ +\ thickness\n\ \ \ \ )\;\n\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\ \ \}\ \{fn\ sdSegmentSq\ fn\ udBezier\}\ \{\n\ \ \ \ vec2\ p\ =\ gl_FragCoord.xy\;\n\ \ \ \ float\ px\ =\ 2.0\;\ //\ sharpness\n\ \ \ \ float\ t\ =\ thickness\;\n\ \ \ \ float\ be\ =\ udBezier(\ p0,\ p1,\ p2,\ p3,\ p\ ).x\;\n\n\ \ \ \ float\ d\ =\ be\;\n\n\ \ \ \ vec4\ col\ =\ mix(\ vec4(0.0),\ color,\ 1.0-smoothstep(t,\ t\ +\ px*1.5,\ d)\ )\;\n\n\ \ \ \ //\ control\ points\n\ \ \ \ //d\ =\ length(p0-p)\;\ col\ =\ mix(\ col,\ vec4(1.0,\ 0.,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p1-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 1.0,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p2-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 0.,\ 1.0,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p3-p)\;\ col\ =\ mix(\ col,\ vec4(1.0),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\n\ \ \ \ return\ col\;\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ curve\ with\ /...options/\ \{\n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...replacedOp ()when /someone/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/recognition/trocr.folk programCode When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ TrOCR\ text\ recognizer\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ TrOCR\ text\ recognizer\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ transformers\ --with\ pillow\ --with\ torch\ --with\ protobuf\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ from\ transformers\ import\ TrOCRProcessor,\ VisionEncoderDecoderModel\n\ \ \ \ \ \ \ \ import\ os\n\ \ \ \ \ \ \ \ import\ sys\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ #\ Determine\ device\ (prefer\ CUDA\ >\ MPS\ >\ CPU)\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ #\ Load\ TrOCR\ model\n\ \ \ \ \ \ \ \ TROCR_PATH\ =\ os.path.expanduser(\"~/folk-data/trocr\")\n\ \ \ \ \ \ \ \ try:\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ disk.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ except\ Exception:\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Model\ not\ saved\;\ loading\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ processor.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ model.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ model.to(device)\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ ocrImage\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ start_time\ =\ time.time()\n\n\ \ \ \ \ \ \ \ #\ Run\ TrOCR\ on\ the\ entire\ image\n\ \ \ \ \ \ \ \ with\ torch.no_grad():\n\ \ \ \ \ \ \ \ \ \ \ \ pixel_values\ =\ processor(image,\ return_tensors=\"pt\").pixel_values.to(device)\n\ \ \ \ \ \ \ \ \ \ \ \ generated_ids\ =\ model.generate(pixel_values)\n\ \ \ \ \ \ \ \ \ \ \ \ text\ =\ processor.batch_decode(generated_ids,\ skip_special_tokens=True)\[0\]\n\n\ \ \ \ \ \ \ \ elapsed\ =\ time.time()\ -\ start_time\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Result:\ \{text\}\ (\{elapsed:.3f\}s)\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ return\ text\n\ \ \ \ \}\n\n\ \ \ \ fn\ TrOCR\ \{im\}\ \{\ return\ \[\$py\ ocrImage\ \$im\]\ \}\n\ \ \ \ Claim\ the\ TrOCR\ text\ recognizer\ is\ \[fn\ TrOCR\]\n\}\n\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...replacedOpt ()when /someone/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/recognition/sam2.folk programCode When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ SAM2\ segmenter\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ SAM2\ segmenter\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n\}\n\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/recognition/craft.folk is replaced with /...replacedOp ()when /someone/ wishes program builtin-programs/recognition/craft.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/recognition/craft.folk programCode When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ CRAFT\ text\ detector\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ CRAFT\ text\ detector\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ \"git+https://github.com/osnr/craft-text-detector.git\"\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ from\ craft_text_detector\ import\ Craft\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ craft\ =\ Craft(output_dir=None,\ crop_type=\"box\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ link_threshold=0.1,\ device=device)\n\ \ \ \ \}\n\ \ \ \ \$py\ def\ detectTextBoxes\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image)\n\n\ \ \ \ \ \ \ \ start_craft\ =\ time.time()\n\ \ \ \ \ \ \ \ result\ =\ craft.detect_text(image_np)\n\ \ \ \ \ \ \ \ boxes\ =\ result\[\"boxes\"\]\n\ \ \ \ \ \ \ \ craft_time\ =\ time.time()\ -\ start_craft\n\n\ \ \ \ \ \ \ \ print(f\"craft:\ Detected\ \{len(boxes)\}\ text\ boxes\ (\{craft_time:.3f\}s)\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ return\ boxes.tolist()\ if\ hasattr(boxes,\ 'tolist')\ else\ boxes\n\ \ \ \ \}\n\n\ \ \ \ fn\ CRAFT\ \{im\}\ \{\ return\ \[\$py\ detectTextBoxes\ \$im\]\ \}\n\ \ \ \ Claim\ the\ CRAFT\ text\ detector\ is\ \[fn\ CRAFT\]\n\}\n\n} {} {__results {}} {}}
when /someone/ wishes program builtin-programs/recognition/contours.folk is replaced with /...replace ()when /someone/ wishes program builtin-programs/recognition/contours.folk is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this builtin-programs/recognition/contours.folk programCode When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ cflags\ -I.\n\ \ \ \ \$cc\ include\ \"vendor/CContour.c\"\n\n\ \ \ \ #\ Binarizes\ the\ first\ channel\ of\ `im`\ at\ `threshold`\ and\ returns\n\ \ \ \ #\ the\ contours\ as\ a\ Tcl\ list.\ Each\ contour\ is\ itself\ a\ Tcl\ list\ of\n\ \ \ \ #\ \{x\ y\}\ pairs.\ If\ epsilon\ >\ 0,\ each\ contour\ is\ simplified\ with\n\ \ \ \ #\ Ramer-Douglas-Peucker.\n\ \ \ \ #\n\ \ \ \ #\ Contours\ are\ scaled\ by\ `scaleX`\ and\ `scaleY`\ so\ that\ they\ can\ be\n\ \ \ \ #\ returned\ in\ real-world\ meters\ (instead\ of\ image-pixel\ space).\n\ \ \ \ #\n\ \ \ \ #\ Discards\ any\ contours\ that\ are\ not\ at\ least\ minLength\ long\n\ \ \ \ #\ (unless\ minLength\ is\ very\ small).\n\ \ \ \ \$cc\ proc\ findImageContours\ \{Image\ im\ int\ threshold\ double\ epsilon\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ scaleX\ double\ scaleY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ minLength\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ w\ =\ (int)im.width\;\n\ \ \ \ \ \ \ \ int\ h\ =\ (int)im.height\;\n\ \ \ \ \ \ \ \ if\ (w\ <\ 3\ ||\ h\ <\ 3)\ return\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ int\ *F\ =\ malloc(sizeof(int)\ *\ (size_t)w\ *\ (size_t)h)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ h\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ *row\ =\ im.data\ +\ (size_t)y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ *Frow\ =\ F\ +\ (size_t)y\ *\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ w\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Frow\[x\]\ =\ (row\[x\ *\ im.components\]\ >\ threshold)\ ?\ 1\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Contour\ *contours\ =\ findContours(F,\ w,\ h)\;\n\ \ \ \ \ \ \ \ free(F)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj\ *outer\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (ptrdiff_t\ c\ =\ 0\;\ c\ <\ arrlen(contours)\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Point\ *pts\ =\ (epsilon\ >\ 0)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ?\ approxPolyDP(contours\[c\].points,\ (float)epsilon)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :\ contours\[c\].points\;\n\ \ \ \ \ \ \ \ \ \ \ \ ptrdiff_t\ n\ =\ arrlen(pts)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (minLength\ >\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ total\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 1\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ (pts\[k\].x\ -\ pts\[k-1\].x)\ *\ scaleX\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ (pts\[k\].y\ -\ pts\[k-1\].y)\ *\ scaleY\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (total\ <\ minLength)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ %g\ prints\ up\ to\ ~13\ chars\ per\ double\;\ round\ up\ to\ give\ headroom.\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ cap\ =\ (size_t)n\ *\ 40\ +\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ char\ *buf\ =\ malloc(cap)\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ off\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 0\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ off\ +=\ snprintf(buf\ +\ off,\ cap\ -\ off,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\ ==\ 0\ ?\ \"\{%g\ %g\}\"\ :\ \"\ \{%g\ %g\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pts\[k\].x\ *\ scaleX,\ pts\[k\].y\ *\ scaleY)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Jim_NewStringObjNoAlloc\ takes\ ownership\ of\ buf.\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ outer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObjNoAlloc(interp,\ buf,\ (int)off))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ freeContours(contours)\;\n\ \ \ \ \ \ \ \ return\ outer\;\n\ \ \ \ \}\n\n\ \ \ \ set\ contourLib\ \[\$cc\ compile\]\n\ \ \ \ Claim\ the\ contour\ library\ is\ \$contourLib\n\}\n\nWhen\ /someone/\ wishes\ /p/\ has\ contours\ \{\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ _\ \{\}\n\}\nWhen\ the\ contour\ library\ is\ /contourLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ contours\ with\ /...opts/\ \{\n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program 62 is replaced with /...opts/ {
set editedTime [dict get $o (
[ m47944:642 (s15546:766) ]
)when /someone/ wishes program 62 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 62} {res {QueryOne! of (62 has demo code /demoCode/) had 0 results. Should be one result!} editedCode {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 4
} fd ::aio.handle15649 code {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 8
} editedTime 1778278213}}
when /someone/ wishes program 62 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith (
[ m47961:638 (s15567:766) ]
)when /someone/ wishes program 62 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 62 programCode {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 8
}} {} {__results {}} {}}
when /someone/ wishes program 11 is replaced with /...opts/ {
set editedTime [dict get $o ()when /someone/ wishes program 11 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 11} {res {QueryOne! of (11 has demo code /demoCode/) had 0 results. Should be one result!} fd ::aio.handle158333 code {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}}}
when /someone/ wishes program 11 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith ()when /someone/ wishes program 11 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 11 programCode {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}} {} {__results {}} {}}
when /someone/ wishes program 54 is replaced with /...opts/ {
set editedTime [dict get $o (
[ m6503:990 (s53017:1175) ]
)when /someone/ wishes program 54 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 54} {res {QueryOne! of (54 has demo code /demoCode/) had 0 results. Should be one result!} editedCode set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n fd ::aio.handle74 code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n editedTime 1778274042}}
when /someone/ wishes program 54 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith (
[ m6517:989 (s53033:1175) ]
)when /someone/ wishes program 54 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 54 programCode set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n} {} {__results {}} {}}
when /someone/ wishes program 82 is replaced with /...opts/ {
set editedTime [dict get $o ()when /someone/ wishes program 82 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 82} {res {QueryOne! of (82 has demo code /demoCode/) had 0 results. Should be one result!} fd ::aio.handle54588 code When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n}}
when /someone/ wishes program 82 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith ()when /someone/ wishes program 82 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 82 programCode When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n} {} {__results {}} {}}
when /someone/ wishes program 63 is replaced with /...opts/ {
set editedTime [dict get $o ()when /someone/ wishes program 63 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 63} {res {QueryOne! of (63 has demo code /demoCode/) had 0 results. Should be one result!} fd ::aio.handle22943 code {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}}}
when /someone/ wishes program 63 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith ()when /someone/ wishes program 63 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 63 programCode {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}} {} {__results {}} {}}
when /someone/ wishes program 83 is replaced with /...opts/ {
set editedTime [dict get $o (
[ m47719:1064 (s64471:1258) ]
)when /someone/ wishes program 83 is replaced with /...opts/ {
set editedTime [dict get $opts editedTime]
Wish $obj is titled "(edited [clock format $editedTime -format "%a, %d %b %Y, %I:%M %p"])"
} with environment {{saveDir /home/folk/folk-data/program} {} {type tag obj 83} {res {QueryOne! of (83 has demo code /demoCode/) had 0 results. Should be one result!} editedCode {Claim $this is a viewport
Wish $this is outlined white} fd ::aio.handle28488 code {Claim $this is a viewport
} editedTime 1781548209}}
when /someone/ wishes program 83 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWith (
[ m47722:1059 (s64483:1262) ]
)when /someone/ wishes program 83 is replaced with /...replacedOpts/ \n\ \ \ \ \ \ \ \ \ \ \ \ SayWithSource\ \$_this\ 1\ 0\ \{\}\ \{\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ when\ \[dict\ get\ \$replacedOpts\ code\]\ with\ environment\ \[list\ \[list\ this\ \$_this\]\]\n\ \ \ \ \ \ \ \ with environment {{_this 83 programCode {Claim $this is a viewport
}} {} {__results {}} {}}
when /someone/ wishes /p/ has neighbors {When {$p} has region /r/ & /p2/ has region /r2/ \n\ \ if\ \{ ()when /someone/ wishes /p/ has neighbors {When {$p} has region /r/ & /p2/ has region /r2/ \n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n} with environment {{this builtin-programs/intersect.folk} {} {}}
when /someone/ wishes /p/ has contours {
Wish $p has contours with _ {}
} with environment {{this ()when /someone/ wishes /p/ has contours {
Wish $p has contours with _ {}
} with environment {{this builtin-programs/recognition/contours.folk} {} {}}
when /someone/ wishes /p/ has contours with /...opts/ \n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ (
[ m59673:1048 () ]
[ m34035:1050 () ]
[ m42655:1052 () ]
[ m1865:1056 () ]
[ m43517:1052 () ]
[ m24913:1054 () ]
[ m65136:1057 () ]
[ m47745:1061 (s64511:1262 s64513:1262) ]
)when /someone/ wishes /p/ has contours with /...opts/ \n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n with environment {{this builtin-programs/recognition/contours.folk} {} {} {contourLib <C:cfileQnzeGL>} {}}
when /someone/ wishes /p/ has camera slice {When camera /cam/ has intrinsics /cameraIntrinsics/ & cam (
[ m3380:1021 (s32232:1210) ]
[ m47753:1064 (s64520:1262) ]
[ m47767:1064 (s64520:1262) ]
[ m27057:1065 () ]
[ m27111:1067 () ]
[ m27171:1064 () ]
[ m27218:1067 () ]
)when /someone/ wishes /p/ has camera slice {When camera /cam/ has intrinsics /cameraIntrinsics/ & camera /cam/ has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when /someone/ wishes /p/ has a canvas {
Wish $p has a canvas with width 1024 height 1024 set ()when /someone/ wishes /p/ has a canvas {
Wish $p has a canvas with width 1024 height 1024 settle 3ms
} with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>}}
when /someone/ wishes /p/ has a canvas with /...options/ \n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ opt (
[ m61822:815 () ]
[ m38728:824 () ]
[ m28704:830 () ]
[ m9757:845 () ]
[ m61029:856 () ]
[ m60262:887 () ]
[ m6676:987 (s31362:0 s53229:1172) ]
)when /someone/ wishes /p/ has a canvas with /...options/ \n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>}}
when /someone/ wishes /p/ draws a /shape/ {
Wish $p draws a $shape with color white
} with environm ()when /someone/ wishes /p/ draws a /shape/ {
Wish $p draws a $shape with color white
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws a /shape/ with /...options/ {When {$p} has region /r/ \n\ \ lassign\ ()when /someone/ wishes /p/ draws a /shape/ with /...options/ {When {$p} has region /r/ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws a /shape/ with radius /rad/ {
Wish $p draws a $shape with radius $r ()when /someone/ wishes /p/ draws a /shape/ with radius /rad/ {
Wish $p draws a $shape with radius $rad
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws a rect with width /w/ height /h/ {
Wish $p draws a rect with width ()when /someone/ wishes /p/ draws a rect with width /w/ height /h/ {
Wish $p draws a rect with width $w height $h
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws an /shape/ {
Wish $p draws a $shape
} with environment {{this built ()when /someone/ wishes /p/ draws an /shape/ {
Wish $p draws a $shape
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws an /shape/ with /...options/ {
Wish $p draws a $shape with {*}$opti ()when /someone/ wishes /p/ draws an /shape/ with /...options/ {
Wish $p draws a $shape with {*}$options
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws text /text/ with /...options/ {When {$p} has region /r/ \n\ \ \ #\ As ()when /someone/ wishes /p/ draws text /text/ with /...options/ {When {$p} has region /r/ \n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ draws text /text/ {
Wish $p draws text $text with color white
} with en ()when /someone/ wishes /p/ draws text /text/ {
Wish $p draws text $text with color white
} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /p/ displays camera slice /slice/ {
Wish $p displays image $slice
} with en (
[ m26534:1067 () ]
[ m26731:1067 () ]
[ m27121:1067 () ]
[ m27412:1067 (s9117:1266) ]
)when /someone/ wishes /p/ displays camera slice /slice/ {
Wish $p displays image $slice
} with environment {{this builtin-programs/camera/slice.folk} {} {}}
when /someone/ wishes /p/ displays image /im/ {
Wish $p displays image $im with scale 1.0
} with (
[ m33950:727 (s14359:846) ]
[ m27129:1065 () ]
[ m27418:1067 (s9125:1262) ]
)when /someone/ wishes /p/ displays image /im/ {
Wish $p displays image $im with scale 1.0
} with environment {{this builtin-programs/draw/image.folk} {} {}}
when /someone/ wishes /p/ displays image /impath/ with /...options/ {When {$p} has resolved geometry (
[ m33945:727 (s14357:865) ]
[ m33952:727 (s14361:865) ]
[ m24409:1066 () ]
[ m25385:1067 () ]
[ m25392:1067 () ]
[ m25693:1064 () ]
[ m25778:1067 () ]
[ m25784:1067 () ]
[ m25827:1067 () ]
[ m25834:943 () ]
[ m25876:1067 () ]
[ m25905:1067 () ]
[ m26024:1065 () ]
[ m26029:1065 () ]
[ m26101:1067 () ]
[ m26216:1067 () ]
[ m26528:1067 () ]
[ m26535:1065 () ]
[ m26542:1067 () ]
[ m26733:1067 () ]
[ m26737:1067 () ]
[ m27072:1064 () ]
[ m27116:1067 (s8783:1266) ]
[ m27122:1066 () ]
[ m27130:1067 () ]
[ m27413:1067 (s9120:1258) ]
[ m27420:1067 (s9127:1266) ]
)when /someone/ wishes /p/ displays image /impath/ with /...options/ {When {$p} has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n} with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {}}
when /someone/ wishes /p/ displays gif /gif/ with /...options/ {When {$p} has resolved geometry /geom (
[ m55296:735 () ]
[ m46382:776 () ]
[ m60160:888 () ]
[ m25741:915 (s2883:1084) ]
)when /someone/ wishes /p/ displays gif /gif/ with /...options/ {When {$p} has resolved geometry /geom/ {
set frames [dict get $gif frames]
set delays [dict get $gif delays]
set totalDuration 0
set cumulativeDelays [list]
foreach d $delays {
if {$d <= 10} { set d 100 }
incr totalDuration $d
lappend cumulativeDelays $totalDuration
}
if {[llength $frames] == 0} { return }
if {[llength $frames] == 1} {
Wish $p displays image [lindex $frames 0] with {*}$options
return
}
When the clock time is /t/ {
set ms [expr {int($t * 1000) % $totalDuration}]
set frameIdx 0
foreach cd $cumulativeDelays {
if {$ms < $cd} { break }
incr frameIdx
}
if {$frameIdx >= [llength $frames]} { set frameIdx 0 }
set im [lindex $frames $frameIdx]
Wish $p displays image $im with {*}$options
}
}} with environment {{this builtin-programs/draw/gif.folk} {} {} {gifLib <C:cfiled3kiwc>} {}}
when /someone/ wishes /p/ runs Unix command /command/ with arguments /args/ \n\tset\ outputKeyName\ \ ()when /someone/ wishes /p/ runs Unix command /command/ with arguments /args/ \n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n with environment {{this builtin-programs/unix-commands.folk} {} {}}
when /someone/ wishes /p/ adds region with /...options/ {When {$p} has region /r/ \n\ \ lassign\ \[re ()when /someone/ wishes /p/ adds region with /...options/ {When {$p} has region /r/ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n} with environment {{this builtin-programs/shapes/region.folk} {} {}}
when /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
} ()when /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
} with environment {{this builtin-programs/regions.folk} {} {}}
when /someone/ wishes region /r/ has highlight /highlighted/ with /...options/ {
set color [dict_g ()when /someone/ wishes region /r/ has highlight /highlighted/ with /...options/ {
set color [dict_getdef $options color white]
set thickness [dict_getdef $options thickness 2]
set layer [dict_getdef $options layer 0]
set dashed [dict_getdef $options dashed false]
set dashlength [dict_getdef $options dashlength 20]
set dashoffset [dict_getdef $options dashoffset 0]
if {$highlighted} {
set verts [region vertices $r]
set edges [region edges $r]
lappend verts [lindex $verts 0]
Wish to draw a dashed stroke with points $verts color $color width $thickness dashlength $dashlength dashoffset $dashoffset layer $layer
}
} with environment {{this builtin-programs/shapes/region.folk} {} {}}
when /someone/ wishes /page/ draws a set of points /points/ with /...options/ {When {$page} has regio ()when /someone/ wishes /page/ draws a set of points /points/ with /...options/ {When {$page} has region /r/ \n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /page/ draws a polyline /points/ with /...options/ {When {$page} has region /r/ ()when /someone/ wishes /page/ draws a polyline /points/ with /...options/ {When {$page} has region /r/ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n} with environment {{this builtin-programs/shapes.folk} {} {shapes {triangle 3 square 4 pentagon 5 hexagon 6 septagon 7 octagon 8 nonagon 9}}}
when /someone/ wishes /page/ is filled with /...options/ {When {$page} has region /region/ {
set po ()when /someone/ wishes /page/ is filled with /...options/ {When {$page} has region /region/ {
set points [region vertices $region]
Wish to draw a polygon with points $points {*}$options
}} with environment {{this builtin-programs/draw/fill.folk} {} {}}
when /someone/ wishes the web server handles route /route/ with /...options/ {
$collectLib Sc (
[ m518:0 () ]
[ m522:0 () ]
[ m537:0 () ]
[ m538:0 () ]
[ m570:0 () ]
[ m576:0 () ]
[ m591:0 () ]
[ m605:0 () ]
[ m613:0 () ]
[ m639:0 () ]
[ m647:0 () ]
[ m655:0 () ]
[ m757:0 () ]
[ m848:0 () ]
[ m1007:0 () ]
[ m1009:0 () ]
[ m1051:0 () ]
[ m1052:0 () ]
[ m4493:0 () ]
[ m4494:0 () ]
[ m25262:0 () ]
[ m47678:0 () ]
[ m47694:0 () ]
[ m47699:0 () ]
[ m47712:0 () ]
[ m47717:0 () ]
)when /someone/ wishes the web server handles route /route/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes the web server handles route /route/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes the GPU loads image /im/ as texture \n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ cop (
[ m18003:0 (s23872:0) ]
[ m18006:0 (s23875:0) ]
[ m18007:0 (s23874:0) ]
[ m18008:0 (s23873:0) ]
[ m24446:854 () ]
[ m25720:1066 () ]
[ m25850:1065 () ]
[ m25909:1067 () ]
[ m25929:1066 () ]
[ m26047:1065 () ]
[ m26114:1067 () ]
[ m26237:1066 () ]
[ m26543:1067 () ]
[ m26557:1067 () ]
[ m26746:1067 () ]
[ m27090:1067 () ]
[ m27135:1066 (s8805:1265) ]
[ m27146:1067 () ]
[ m27433:1067 (s9146:1266) ]
)when /someone/ wishes the GPU loads image /im/ as texture \n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n with environment {{this builtin-programs/gpu/textures.folk} {} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuLib <C:cfileog6zwp>} {} {vmaDll /tmp/cfilequ8HAs.so} {} {imageLib <C:cfileV8MUaU>} {^defineVulkanHandleType {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} gpuc ::<reference.<C______>.00000000000000000008> gpuTextureLib <C:cfileHQKyt3>}}
when /someone/ wishes the GPU creates canvas /id/ with /...options/ \n\ \ \ \ \ \ \ \ puts\ \"Create\ (
[ m23576:0 (s31228:0 s31229:0) ]
[ m23669:0 (s31365:0 s31366:0) ]
[ m5178:43 (s12988:51 s12989:51) ]
[ m28091:624 (s55976:745 s55977:745) ]
[ m57069:683 (s38522:827 s38526:827) ]
[ m33894:727 (s14328:865 s14330:865) ]
[ m6546:963 (s53113:1170 s53114:1174) ]
[ m42513:1051 (s60008:1248 s60009:1248) ]
)when /someone/ wishes the GPU creates canvas /id/ with /...options/ \n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>}}
when /someone/ wishes /tag/ has resolved geometry \n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (4 (
[ m25654:915 (s2781:1088) ]
[ m6390:990 (s52871:1153) ]
[ m3057:1024 (s31837:1157) ]
[ m44637:1039 (s51832:1233) ]
[ m23346:1061 (s14672:1259) ]
[ m47700:1059 (s64449:987) ]
)when /someone/ wishes /tag/ has resolved geometry \n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {}}
when /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSan (
[ m27243:1067 () ]
[ m27264:1065 () ]
[ m27326:1066 () ]
[ m27383:1067 () ]
[ m27443:1063 () ]
[ m27455:1067 () ]
[ m27587:1066 (s9335:1266) ]
[ m27600:1066 (s9344:1262) ]
)when /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
} with environment {{this builtin-programs/decorations/label.folk} {} {}}
when /someone/ wishes /thing/ is outlined /color/ {When {$thing} has resolved geometry /geom/ \n\ \ \ (
[ m6699:990 (s53321:1175) ]
[ m47728:1063 (s64491:1262) ]
[ m47734:1061 (s64500:1262) ]
[ m25811:1067 () ]
[ m25895:943 () ]
[ m26565:1067 () ]
[ m27028:1067 () ]
[ m27143:1066 () ]
[ m27192:1067 () ]
[ m27239:1067 (s8920:1265) ]
[ m27404:1066 () ]
[ m27489:1064 () ]
[ m27492:1062 (s9208:1266) ]
[ m27545:1067 (s9276:1266) ]
)when /someone/ wishes /thing/ is outlined /color/ {When {$thing} has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n} with environment {{this builtin-programs/decorations/outline.folk} {} {}}
when /someone/ wishes folk-sva uses camera /cameraPath/ with /...options/ \n\ \ \ \ if\ \{!\[string\ (
[ m942:0 () ]
)when /someone/ wishes folk-sva uses camera /cameraPath/ with /...options/ \n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n with environment {{this builtin-programs/camera/rpi.folk} {} {makeCamera {
set cpp [C++]
$cpp extend $imageLib
$cpp include <iostream>
$cpp include <iomanip>
$cpp include <mutex>
$cpp include <condition_variable>
$cpp include <queue>
$cpp include <sys/mman.h>
$cpp include <libcamera/libcamera.h>
# osnr: HACK: just throwing any possible path in.
$cpp cflags -I/usr/local/include/libcamera -I/usr/include/libcamera
$cpp endcflags -lcamera
$cpp code {
using namespace libcamera;
std::unique_ptr<CameraManager> cm;
std::shared_ptr<Camera> camera;
std::unique_ptr<CameraConfiguration> config;
FrameBufferAllocator *allocator;
// This vector always owns all the request objects.
std::vector<std::unique_ptr<Request>> requests;
std::mutex completedRequestsMutex;
std::queue<Request *> completedRequests;
std::condition_variable completedRequestsCv;
uint32_t frameWidth;
uint32_t frameHeight;
uint32_t frameBytesPerRow;
static void requestComplete(Request *request);
}
$cpp proc cameraOpen {char* id int width int height} void {
cm = std::make_unique<CameraManager>();
cm->start();
std::cout << "camera/rpi: cameras:" << std::endl;
for (auto const &camera : cm->cameras()) {
std::cout << " - " << camera->id() << std::endl;
}
camera = cm->get(id);
FOLK_ENSURE(camera != nullptr);
camera->acquire();
config = camera->generateConfiguration({ StreamRole::Viewfinder });
StreamConfiguration &streamConfig = config->at(0);
streamConfig.size = Size(width, height);
streamConfig.pixelFormat = PixelFormat::fromString("YUV420");
config->validate();
frameWidth = streamConfig.size.width;
frameHeight = streamConfig.size.height;
frameBytesPerRow = streamConfig.stride;
std::cout << "frameWidth: " << frameWidth << " frameHeight: " << frameHeight << std::endl;
camera->configure(config.get());
allocator = new FrameBufferAllocator(camera);
for (StreamConfiguration &cfg : *config) {
int ret = allocator->allocate(cfg.stream());
if (ret < 0) {
FOLK_ERROR("Can't allocate buffers");
}
size_t allocated = allocator->buffers(cfg.stream()).size();
std::cout << "camera/rpi: Allocated " << allocated << " buffers for stream" << std::endl;
// for (PixelFormat &format : cfg.formats().pixelformats()) {
// std::cout << "camera/rpi: Stream supports format " << format << std::endl;
// for (Size &size : cfg.formats().sizes(format)) {
// std::cout << " -> supports size " << size << std::endl;
// }
// }
}
Stream *stream = streamConfig.stream();
assert(streamConfig.pixelFormat.toString() == "YUV420");
const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator->buffers(stream);
for (unsigned int i = 0; i < buffers.size(); ++i) {
std::unique_ptr<Request> request = camera->createRequest();
if (!request) {
FOLK_ERROR("camera/rpi: Can't create request");
}
const std::unique_ptr<FrameBuffer> &buffer = buffers[i];
int ret = request->addBuffer(stream, buffer.get());
if (ret < 0) {
FOLK_ERROR("camera/rpi: Can't set buffer for request");
}
ControlList &controls = request->controls();
controls.set(controls::AeEnable, false);
controls.set(controls::ExposureTime, 35000);
controls.set(controls::AfMode, controls::AfModeManual);
// Focus 30cm away (0.3m -> 1/0.3 = 3.3).
controls.set(controls::LensPosition, 1.6);
requests.push_back(std::move(request));
}
camera->requestCompleted.connect(requestComplete);
camera->start();
for (std::unique_ptr<Request> &request : requests) {
camera->queueRequest(request.get());
}
}
$cpp code {
static void requestComplete(Request *request) {
if (request->status() == Request::RequestCancelled) {
return;
}
completedRequestsMutex.lock();
completedRequests.push(request);
completedRequestsMutex.unlock();
completedRequestsCv.notify_one();
}
static void processRequestAndCopyFrame(Request *request, Image im) {
const Request::BufferMap &buffers = request->buffers();
assert(buffers.size() == 1);
for (auto bufferPair : buffers) {
// (Unused) Stream *stream = bufferPair.first;
FrameBuffer *buffer = bufferPair.second;
const FrameMetadata &metadata = buffer->metadata();
assert(metadata.planes().size() == 3);
assert(buffer->planes().size() == 3);
auto &plane = buffer->planes()[0];
int fd = plane.fd.get();
void *addr = mmap64(NULL, plane.length, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == MAP_FAILED) {
FOLK_ERROR("camera/rpi: MAP_FAILED");
}
void *planeData = (uint8_t *)addr + plane.offset;
memcpy(im.data, planeData, frameHeight * frameBytesPerRow);
munmap(addr, plane.length);
}
}
}
$cpp proc newImage {} Image {
uint32_t width = frameWidth;
uint32_t height = frameHeight;
int components = 1;
uint8_t *data = (uint8_t *) malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data
};
}
$cpp proc freeImage {Image image} void {
free(image.data);
}
$cpp proc grayFrame {} Image {
Request *latestRequest = nullptr;
// We want to drain the queue of completed requests.
std::unique_lock lk(completedRequestsMutex);
completedRequestsCv.wait(lk, []{
return !completedRequests.empty();
});
while (!completedRequests.empty()) {
if (latestRequest != nullptr) {
// We're skipping this request, because we have a
// newer one in the queue. Requeue it.
latestRequest->reuse(Request::ReuseBuffers);
camera->queueRequest(latestRequest);
}
latestRequest = completedRequests.front();
completedRequests.pop();
}
lk.unlock();
if (latestRequest == nullptr) {
FOLK_ERROR("No new frame yet");
}
Image im = newImage();
processRequestAndCopyFrame(latestRequest, im);
/* Re-queue the Request to the camera. */
latestRequest->reuse(Request::ReuseBuffers);
camera->queueRequest(latestRequest);
return im;
}
$cpp compile
}} {imageLib <C:cfileV8MUaU>} {}}
when /someone/ wishes folk-sva uses camera /camera/ with /...options/ \n\ \ \ \ if\ \{!\[string\ matc (
[ m1502:0 (s2605:0 s2606:0) ]
)when /someone/ wishes folk-sva uses camera /camera/ with /...options/ \n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {jpegLib <C:cfileZXB3iE>} {camLib <C:cfilel9mgpH> camc ::<reference.<C______>.00000000000000000002>}}
when /someone/ wishes folk-sva uses camera /camera/ with /...opts/ {
$collectLib ScheduleReco (
[ m62009:1055 () ]
)when /someone/ wishes folk-sva uses camera /camera/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-inde ()when /someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-inde (
[ m61912:1053 () ]
)when /someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes folk-sva uses display glfw with /...any/ {
gpuInit true
} with envi ()when /someone/ wishes folk-sva uses display glfw with /...any/ {
gpuInit true
} with environment {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} ^gpuInit {useGlfw {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
} {builtin-programs/gpu/gpu.folk 34}}} {} {}}
when /someone/ wishes folk-sva uses display monitor with /...usingOpts/ {
$collectLib Schedul (
[ m61846:1044 () ]
[ m61849:1040 () ]
)when /someone/ wishes folk-sva uses display monitor with /...usingOpts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes folk-sva uses display /display/ with /...opts/ {
$collectLib ScheduleRe (
[ m61938:1049 () ]
[ m61939:1052 () ]
)when /someone/ wishes folk-sva uses display /display/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes folk-sva uses display /display/ with /...opts/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes editor /editor/ has a print preview {When editor {$editor} has selected program ()when /someone/ wishes editor /editor/ has a print preview {When editor {$editor} has selected program /program/ \n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n} with environment {{this builtin-programs/editor/print-editor.folk} {} {^editorToPrintOptions {editor \n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n {builtin-programs/editor/print-editor.folk 1}}} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {}}
when /someone/ wishes camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposu (
[ m1679:0 () ]
)when /someone/ wishes camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposure time /exposureTimeUs/ us {
$camLib setExposure $camObj [expr {int($exposureTimeUs / 100)}]
} with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {jpegLib <C:cfileZXB3iE>} {camLib <C:cfilel9mgpH> camc ::<reference.<C______>.00000000000000000002>} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 options {width 1920 height 1080 framerate 60.0}} {bufferCount 2 ^runCamera {camObjVar \n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ {builtin-programs/camera/usb.folk 306}} width 1920 height 1080 i 5 camObj {(Camera*) 0x79d18806be50} camObjVar camObj}}
when /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ ()when /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n with environment {{this builtin-programs/points-at.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {}}
when /someone/ wishes 82 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect (
[ m27324:1067 () ]
[ m27327:1067 () ]
[ m27368:1066 () ]
[ m27385:1067 () ]
[ m27454:1062 () ]
[ m27458:1063 () ]
[ m27585:1064 () ]
[ m27590:1067 () ]
)when /someone/ wishes 82 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 82 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 82 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /someone/ wishes 82 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 82 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 82 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 82 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 82 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 82 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 82 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 82 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 82 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 82 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 82 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 11 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect ()when /someone/ wishes 11 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 11 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 11 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 11 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 11 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 11 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 11 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 11 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 11 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 11 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 11 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 11 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /someone/ wishes 11 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 11 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-display is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-display is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-display is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-display is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-display is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-display is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-display is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-display is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-display is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-display is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-display is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-display is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-display is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-display is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-display is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 62 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect ()when /someone/ wishes 62 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 62 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 62 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 62 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 62 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 62 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 62 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 62 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 62 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 62 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 62 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 62 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs (
[ m16204:1053 () ]
)when /someone/ wishes 62 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 62 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 63 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect ()when /someone/ wishes 63 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 63 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 63 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 63 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 63 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 63 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /someone/ wishes 63 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 63 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 63 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 63 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 63 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 63 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 63 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 63 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-1 is outlined /color/ {When 54-frame-1 has quad /frameQuad/ \n\n\ \ \ (
[ m24934:1057 () ]
[ m25407:1067 () ]
[ m25653:1067 () ]
[ m25879:1067 () ]
[ m26150:1067 () ]
)when /someone/ wishes 54-frame-1 is outlined /color/ {When 54-frame-1 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 1 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-1 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-1 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-1 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-1 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-1 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-1 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-1 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-1 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-1 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-1 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-1 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-1 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-1 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-1 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-1 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-2 is outlined /color/ {When 54-frame-2 has quad /frameQuad/ \n\n\ \ \ (
[ m23806:1066 () ]
[ m24451:991 () ]
[ m25477:1064 () ]
[ m26254:1066 () ]
)when /someone/ wishes 54-frame-2 is outlined /color/ {When 54-frame-2 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 2 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-2 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-2 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-2 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-2 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-2 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-2 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-2 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-2 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-2 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-2 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-2 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-2 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-2 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-2 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-2 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-3 is outlined /color/ {When 54-frame-3 has quad /frameQuad/ \n\n\ \ \ (
[ m19559:1058 () ]
[ m19701:1051 () ]
[ m21457:1067 () ]
[ m21872:1062 () ]
[ m23793:1062 () ]
[ m24400:678 () ]
[ m26194:1061 () ]
[ m27232:1067 (s8912:1266) ]
)when /someone/ wishes 54-frame-3 is outlined /color/ {When 54-frame-3 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 3 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-3 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-3 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-3 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-3 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-3 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-3 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-3 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-3 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-3 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-3 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-3 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-3 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-3 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-3 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-3 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-4 is outlined /color/ {When 54-frame-4 has quad /frameQuad/ \n\n\ \ \ (
[ m21812:1066 () ]
[ m22947:1067 () ]
[ m23744:1066 () ]
[ m24145:1067 () ]
[ m24987:1063 () ]
[ m25969:1067 () ]
[ m27183:1067 () ]
)when /someone/ wishes 54-frame-4 is outlined /color/ {When 54-frame-4 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 4 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-4 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-4 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-4 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-4 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-4 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-4 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-4 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-4 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-4 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-4 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-4 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-4 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-4 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-4 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-4 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-5 is outlined /color/ {When 54-frame-5 has quad /frameQuad/ \n\n\ \ \ (
[ m27132:1066 () ]
)when /someone/ wishes 54-frame-5 is outlined /color/ {When 54-frame-5 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 5 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-5 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-5 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-5 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-5 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-5 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-5 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-5 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-5 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-5 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-5 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-5 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-5 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-5 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-5 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-5 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-6 is outlined /color/ {When 54-frame-6 has quad /frameQuad/ \n\n\ \ \ (
[ m23169:1067 () ]
[ m23625:1067 () ]
[ m24074:1066 () ]
[ m24891:1066 () ]
[ m25619:1067 () ]
[ m25931:1067 () ]
[ m26551:1067 () ]
)when /someone/ wishes 54-frame-6 is outlined /color/ {When 54-frame-6 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ } with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 6 frameGeom {width 0.1055 height 0.0695}}}
when /someone/ wishes 54-frame-6 is labelled /text/ with /...options/ {
$collectLib ScheduleR ()when /someone/ wishes 54-frame-6 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-6 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-6 is left-margined /text/ {
$collectLib ScheduleRecollect! $pa ()when /someone/ wishes 54-frame-6 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-6 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-6 is right-margined /text/ {
$collectLib ScheduleRecollect! $p ()when /someone/ wishes 54-frame-6 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-6 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-6 is footnoted /text/ {
$collectLib ScheduleRecollect! $patter ()when /someone/ wishes 54-frame-6 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-6 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54-frame-6 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54-frame-6 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54-frame-6 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect (
[ m26583:1067 () ]
[ m26586:1066 () ]
[ m27242:1067 () ]
[ m27245:1066 () ]
[ m27441:1067 () ]
[ m27445:1063 () ]
[ m27596:1067 () ]
[ m27601:1066 () ]
)when /someone/ wishes 54 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /someone/ wishes 54 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 54 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 54 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 54 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 54 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 54 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 83 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect ()when /someone/ wishes 83 is labelled /text/ with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 83 is labelled /text/ with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 83 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ wishes 83 is left-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 83 is left-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 83 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $ ()when /someone/ wishes 83 is right-margined /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 83 is right-margined /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 83 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settl ()when /someone/ wishes 83 is footnoted /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 83 is footnoted /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ wishes 83 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs (
[ m2157:1066 () ]
)when /someone/ wishes 83 is titled /text/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ wishes 83 is titled /text/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims /editor/ is an editor \n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$d ()when /someone/ claims /editor/ is an editor \n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
when /someone/ claims tag 11 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ claims tag 11 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 11 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims tag 82 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s (
[ m6663:984 () ]
)when /someone/ claims tag 82 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 82 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims tag 62 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ claims tag 62 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 62 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims tag 63 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ claims tag 63 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 63 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims tag 54 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s ()when /someone/ claims tag 54 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 54 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ claims tag 83 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $s (
[ m47711:1064 () ]
)when /someone/ claims tag 83 has geometry /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ claims tag 83 has geometry /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when /someone/ detects tags /tags/ on camera /camera/ at timestamp /timestamp/ in time /aprilTime/ {
(
[ m27199:1066 () ]
[ m27362:1067 () ]
[ m27467:1062 () ]
[ m27499:1066 () ]
[ m27687:1067 () ]
)when /someone/ detects tags /tags/ on camera /camera/ at timestamp /timestamp/ in time /aprilTime/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/someone/ detects tags /tags/ on camera /camera/ at timestamp /timestamp/ in time /aprilTime/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/music.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/music.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/music.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/music.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/music.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/music.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/errors.folk does not run {
$collectLib ScheduleRec ()when /any/ wishes program builtin-programs/errors.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/errors.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/errors.folk is replaced with /...anything/ {
$coll ()when /any/ wishes program builtin-programs/errors.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/errors.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/terminal.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/terminal.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/terminal.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/group.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/group.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/group.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/group.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/group.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/group.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/mask-tags.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/mask-tags.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/mask-tags.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/laser.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/laser.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/laser.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/laser.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/laser.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/laser.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/usb.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/camera/usb.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/usb.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/demos.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/demos.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/demos.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/demos.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/demos.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/demos.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/points-at.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/points-at.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/points-at.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/programs.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/programs.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/programs.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/programs.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/programs.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/programs.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/intersect.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/intersect.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/intersect.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/tags-to-quads.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/tags-to-quads.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/tags-to-quads.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/apriltags.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/apriltags.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/apriltags.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/regions.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/regions.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/regions.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/regions.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/regions.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/regions.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/terminal-ui.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/terminal-ui.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/terminal-ui.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/slice.folk does not run {
$collectLib Sched ()when /any/ wishes program builtin-programs/camera/slice.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/slice.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/shapes.folk does not run {
$collectLib ScheduleRec ()when /any/ wishes program builtin-programs/shapes.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/shapes.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/ {
$coll ()when /any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/sprites.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/sprites.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/sprites.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/esc-pos.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/esc-pos.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/esc-pos.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/keyboard.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/keyboard.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/keyboard.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/audio.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/audio.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/audio.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/audio.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/audio.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/audio.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/tags-geometry.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/tags-geometry.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/tags-geometry.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/title.folk does not run {
$collectLib ScheduleReco ()when /any/ wishes program builtin-programs/title.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/title.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/title.folk is replaced with /...anything/ {
$colle ()when /any/ wishes program builtin-programs/title.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/title.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/connections.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/connections.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/connections.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/connections.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/connections.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/connections.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/unix-commands.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/unix-commands.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/unix-commands.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/fswatch.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/fswatch.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/fswatch.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/enumerate.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/camera/enumerate.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/enumerate.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor-control.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/editor-control.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor-control.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display-saver.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/display-saver.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display-saver.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/image.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/draw/image.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/image.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/apriltags.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/draw/apriltags.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/apriltags.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/fill.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/draw/fill.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/fill.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/dashed-line.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/draw/dashed-line.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/dashed-line.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/line.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/draw/line.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/line.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/gif.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/draw/gif.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/gif.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/circle.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/draw/circle.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/circle.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/color-map.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/draw/color-map.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/color-map.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/gif-lib.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/image/gif-lib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/gif-lib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/text.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/draw/text.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/text.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/jpeg-lib.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/image/jpeg-lib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/jpeg-lib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/image-lib.folk does not run {
$collectLib Sc ()when /any/ wishes program builtin-programs/image/image-lib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/image-lib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/print/print.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/print/print.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/print/print.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/png-lib.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/image/png-lib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/png-lib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/dep-graph.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/web/dep-graph.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/dep-graph.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/nav.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/web/nav.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/nav.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/setup.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/web/setup.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/setup.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/textures.folk does not run {
$collectLib Sched ()when /any/ wishes program builtin-programs/web/textures.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/textures.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/block-stats.folk does not run {
$collectLib Sc ()when /any/ wishes program builtin-programs/web/block-stats.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/block-stats.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/program.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/web/program.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/program.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/holds.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/web/holds.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/holds.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/db-lib.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/web/db-lib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/db-lib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/threads.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/web/threads.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/threads.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/web.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/web/web.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/web.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/quads.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/web/quads.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/quads.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/statements.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/web/statements.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/statements.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/keyboards.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/web/keyboards.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/keyboards.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/trie-graph.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/web/trie-graph.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/trie-graph.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/page.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/web/page.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/page.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/atomicallys.folk does not run {
$collectLib Sc ()when /any/ wishes program builtin-programs/web/atomicallys.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/atomicallys.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/new.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/web/new.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/new.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/log.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/web/log.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/log.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/camera-frame.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/web/camera-frame.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/camera-frame.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/apriltag-frame.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/web/apriltag-frame.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/apriltag-frame.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/report.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/web/report.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/report.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/printed-programs.folk does not run {
$collectL ()when /any/ wishes program builtin-programs/web/printed-programs.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/printed-programs.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/ { ()when /any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/index.folk does not run {
$collectLib Schedule ()when /any/ wishes program builtin-programs/web/index.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/index.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/ {
$c ()when /any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/camera.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/web/camera.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/camera.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run {
$c ()when /any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anyt ()when /any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run {
$co ()when /any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anyth ()when /any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run {
$coll ()when /any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anythin ()when /any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/model.folk does not run {
$collectLib Sc ()when /any/ wishes program builtin-programs/calibrate/model.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/model.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/draw-model.folk does not run {
$collectL ()when /any/ wishes program builtin-programs/calibrate/draw-model.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/draw-model.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/ { ()when /any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/refine.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/calibrate/refine.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/refine.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/enumerate.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/gpu/enumerate.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/enumerate.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/matlib.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/calibrate/matlib.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/matlib.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibrate.folk does not run {
$collectLi ()when /any/ wishes program builtin-programs/calibrate/calibrate.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibrate.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/pipelines.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/gpu/pipelines.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/pipelines.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/gpu.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/gpu/gpu.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/gpu.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/textures.folk does not run {
$collectLib Sched ()when /any/ wishes program builtin-programs/gpu/textures.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/textures.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/draw.folk does not run {
$collectLib ScheduleR ()when /any/ wishes program builtin-programs/gpu/draw.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/draw.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/ {
$co ()when /any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/toy-shader.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/gpu/toy-shader.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/toy-shader.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/canvases.folk does not run {
$collectLib Sched ()when /any/ wishes program builtin-programs/gpu/canvases.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/canvases.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/vma.folk does not run {
$collectLib ScheduleRe ()when /any/ wishes program builtin-programs/gpu/vma.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/vma.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/ {
$col ()when /any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/rpi.folk does not run {
$collectLib Schedul ()when /any/ wishes program builtin-programs/camera/rpi.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/rpi.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/ {
$ ()when /any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/decorations/label.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/decorations/label.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/decorations/label.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/decorations/outline.folk does not run {
$collectLi ()when /any/ wishes program builtin-programs/decorations/outline.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/decorations/outline.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/draw-editor.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/editor/draw-editor.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/draw-editor.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/editor-utils.folk does not run {
$collectLi ()when /any/ wishes program builtin-programs/editor/editor-utils.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/editor-utils.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/editor.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/editor/editor.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/editor.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/print-editor.folk does not run {
$collectLi ()when /any/ wishes program builtin-programs/editor/print-editor.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/print-editor.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/save-programs.folk does not run {
$collectL ()when /any/ wishes program builtin-programs/saving/save-programs.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/save-programs.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/ { ()when /any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/saving.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/saving/saving.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/saving.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/migrate.folk does not run {
$collectLib Sch ()when /any/ wishes program builtin-programs/saving/migrate.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/migrate.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/save-holds.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/saving/save-holds.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/save-holds.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/shapes/region.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/shapes/region.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/shapes/region.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display/arc.folk does not run {
$collectLib Schedu ()when /any/ wishes program builtin-programs/display/arc.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display/arc.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display/curve.folk does not run {
$collectLib Sche ()when /any/ wishes program builtin-programs/display/curve.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display/curve.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/trocr.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/recognition/trocr.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/trocr.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/sam2.folk does not run {
$collectLib S ()when /any/ wishes program builtin-programs/recognition/sam2.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/sam2.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/craft.folk does not run {
$collectLib ()when /any/ wishes program builtin-programs/recognition/craft.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/craft.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/ {
()when /any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/contours.folk does not run {
$collectL ()when /any/ wishes program builtin-programs/recognition/contours.folk does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/contours.folk does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/ { ()when /any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 62 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 62 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 62 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 62 is replaced with /...anything/ {
$collectLib ScheduleRecollect! (
[ m48159:639 () ]
)when /any/ wishes program 62 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 62 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 11 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 11 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 11 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 11 is replaced with /...anything/ {
$collectLib ScheduleRecollect! ()when /any/ wishes program 11 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 11 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 54 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 54 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 54 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 54 is replaced with /...anything/ {
$collectLib ScheduleRecollect! (
[ m6590:987 () ]
)when /any/ wishes program 54 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 54 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 82 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 82 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 82 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 82 is replaced with /...anything/ {
$collectLib ScheduleRecollect! ()when /any/ wishes program 82 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 82 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 63 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 63 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 63 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 63 is replaced with /...anything/ {
$collectLib ScheduleRecollect! ()when /any/ wishes program 63 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 63 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 83 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs ()when /any/ wishes program 83 does not run {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 83 does not run} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes program 83 is replaced with /...anything/ {
$collectLib ScheduleRecollect! (
[ m47777:1063 () ]
)when /any/ wishes program 83 is replaced with /...anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes program 83 is replaced with /...anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes to calibrate camera /any/ to display /any/ /...etc/ {
$collectLib ScheduleR ()when /any/ wishes to calibrate camera /any/ to display /any/ /...etc/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ wishes folk-sva uses display glfw with /...any/ {
$collectLib ScheduleRecollect! $ ()when /any/ wishes folk-sva uses display glfw with /...any/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ wishes folk-sva uses display glfw with /...any/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ claims a calibration from camera /cam/ to display /disp/ is /anything/ {
$collectL (
[ m922:0 () ]
)when /any/ claims a calibration from camera /cam/ to display /disp/ is /anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ claims a calibration from camera /cam/ to display /disp/ is /anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ claims a calibration from camera /cam/ to display monitor is /anything/ {
$collect (
[ m23662:0 () ]
)when /any/ claims a calibration from camera /cam/ to display monitor is /anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ claims a calibration from camera /cam/ to display monitor is /anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ claims a calibration from camera /camera/ to display /display/ is /anything/ {
$co (
[ m1067:0 () ]
)when /any/ claims a calibration from camera /camera/ to display /display/ is /anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ claims a calibration from camera /camera/ to display /display/ is /anything/} settle 0ms} {settleMs 0 settleNs 0}}
when /any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-ind (
[ m4498:0 () ]
)when /any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is /anything/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is /anything/} settle 0ms} {settleMs 0 settleNs 0}}
when {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard (
[ m251:0 (s395:0 s397:0) ]
)when {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard-shortcuts.folk, match m10029:6: Failed to restart folk.service: Interactive authentication required.
#
# TODO: Figure out how to do this with less powerful permissions than `sudo`. (@cwervo)
# Keyboard shortcuts
# ---
# Alt + Esc: Restart Folk
# Alt + F1: Stop Folk completely (note: need to ssh to restart Folk)
# Alt-Esc on most keyboards
Subscribe: keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
}
# Console_1 corresponds to Alt-F1 on most keyboards
Subscribe: keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
}
} with environment {{this builtin-programs/keyboard-shortcuts.folk}}
when {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code (
[ m259:0 (s405:0 s408:0 s410:0 s411:0 s413:0 s414:0 s416:0 s417:0 s419:0) ]
)when {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
Claim 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
Claim 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
Claim 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
Claim 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
Claim 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
Claim 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
Claim 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
Claim 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
} with environment {{this builtin-programs/demos.folk}}
when #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$th (
[ m258:0 (s425:0) ]
)when #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n with environment {{this builtin-programs/terminal.folk}}
when When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n (
[ m260:0 (s415:0) ]
)when When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ width\ /projWidth/\ height\ /projHeight/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ intrinsics\ /projectorIntrinsics/\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/mask-tags.folk}}
when {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr (
[ m262:0 (s427:0 s433:0) ]
)when {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
}
When /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
}
} with environment {{this builtin-programs/errors.folk}}
when return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contai (
[ m265:0 () ]
)when return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contains\ /...programs/\ \{\n\ \ \ \ Wish\ tag\ \$group\ is\ stabilized\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ claim\ 'tag'\ specifically\ so\ it\ doesn't\ run\ twice\n\ \ \ \ \ \ \ \ Claim\ tag\ \$program\ has\ a\ program\n\ \ \ \ \}\n\}\n\n#\ figure\ out\ the\ text\ to\ display\ below\nWhen\ group\ /group/\ contains\ /...programs/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ /program/\ is\ titled\ /title/\]\ are\ /results/\ \{\n\ \ \ \ set\ programTitles\ \[dict\ create\]\n\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ programId\ \[dict\ get\ \$result\ program\]\n\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$programs\ \$programId\]\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ programTitles\ \$programId\ \[dict\ get\ \$result\ title\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ programTitleText\ \"\"\n\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ set\ title\ \[dict_getdef\ \$programTitles\ \$program\ \"(no\ title)\"\]\n\ \ \ \ \ \ \ \ append\ programTitleText\ \\n\ \$program\ \":\ \"\ \$title\n\ \ \ \ \}\n\n\ \ \ \ Claim\ group\ \$group\ has\ program\ titles\ \$programTitleText\n\}\n\n#\ display\ said\ text\nWhen\ group\ /group/\ has\ program\ titles\ /programTitles/\ &\\\n\ \ \ \ \ /group/\ has\ region\ /r/\ \{\n\ \ \ \ set\ radians\ \[region\ angle\ \$r\]\n\ \ \ \ set\ pos\ \[region\ topleft\ \[region\ move\ \$r\ down\ 40px\ right\ 15px\]\]\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ text\ \$programTitles\ scale\ 0.7\ radians\ \$radians\ anchor\ topleft\n\}\n with environment {{this builtin-programs/group.folk}}
when When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ c (
[ m270:0 (s443:0) ]
)when When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/laser.folk}}
when {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set (
[ m271:0 () ]
)when {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set musicDir $::env(HOME)/music
exec mkdir -p $musicDir
# https://raw.githubusercontent.com/tidalcycles/Tidal/main/BootTidal.hs
set bootTidal {
:set -XOverloadedStrings
:set prompt ""
import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)
hSetEncoding stdout utf8
tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})
:{
let only = (hush >>)
p = streamReplace tidal
hush = streamHush tidal
panic = do hush
once $ sound "superpanic"
list = streamList tidal
mute = streamMute tidal
unmute = streamUnmute tidal
unmuteAll = streamUnmuteAll tidal
unsoloAll = streamUnsoloAll tidal
solo = streamSolo tidal
unsolo = streamUnsolo tidal
once = streamOnce tidal
first = streamFirst tidal
asap = once
nudgeAll = streamNudgeAll tidal
all = streamAll tidal
resetCycles = streamResetCycles tidal
setCycle = streamSetCycle tidal
setcps = asap . cps
getcps = streamGetcps tidal
getnow = streamGetnow tidal
xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
jump i = transition tidal True (Sound.Tidal.Transition.jump) i
jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
d13 = p 13
d14 = p 14
d15 = p 15
d16 = p 16
:}
:{
let getState = streamGet tidal
setI = streamSetI tidal
setF = streamSetF tidal
setS = streamSetS tidal
setR = streamSetR tidal
setB = streamSetB tidal
:}
:set prompt "tidal> "
:set prompt-cont ""
default (Pattern String, Integer, Double)
}
set scStartup [open $musicDir/startup.sc w]
# via https://club.tidalcycles.org/t/tidal-synth-doesnt-work/800 -- it
# doesn't work if you just do SuperDirt.start; for some reason
puts $scStartup {(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 2048; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt.stop; // stop any old ones, avoid duplicate dirt (if it is nil, this won't do anything)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
SuperDirt.default = ~dirt; // make this instance available in sclang (optional)
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
// directly below here, in your own copy of this file, you could add further code that you want to call on startup
// this makes sure the server and ~dirt are running
// you can keep this separate and make it easier to switch between setups
// by using "path/to/my/file.scd".load and if necessary commenting out different load statements
// ...
};
s.latency = 0.3; // increase this if you get "late" messages
};
);}
close $scStartup
set uid [exec id -u $::env(USER)]
set ::env(DBUS_SESSION_BUS_ADDRESS) "unix:path=/run/user/$uid/bus"
exec rm -f $musicDir/music.log
fn musicExec {args} {
if {[lindex $args end] eq "&"} {
exec {*}[lreplace $args end end] >>$musicDir/music.log 2>>$musicDir/music.log &
} else {
exec {*}$args >>$musicDir/music.log 2>>$musicDir/music.log
}
}
fn musicFinishSetup {} {
if {$::thisNode eq "folk-hex"} {
exec jackd -d alsa -d hdmi:CARD=NVidia -r 48000 -p 1024 -n 2 &
} elseif {$::thisNode eq "folk-sva"} {
exec jackd -d alsa -d hdmi:CARD=Generic,DEV=1 -r 48000 -p 1024 -n 2 &
}
catch {exec pkill ghci}
catch {exec pkill ghc}
catch {exec pkill sclang}
catch {exec pkill scsynth}
sleep 0.4
set ::env(QT_QPA_PLATFORM) offscreen
musicExec sclang $musicDir/startup.sc &
set fifo $musicDir/tidal-input
exec rm -f $fifo
exec mkfifo $fifo
sleep 0.2
musicExec sh -c "ghci < $fifo" &
set fifoId [open $fifo w]
puts $fifoId $bootTidal; flush $fifoId
# We keep $fifoId open so that ghci doesn't get an EOF.
}
while true {
puts "music: Waiting for D-Bus."
sleep 0.2
if {[file exists /run/user/$uid/bus]} {
puts "music: Found D-Bus."
musicFinishSetup
break
}
}
} with environment {{this builtin-programs/music.folk}}
when When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ envir (
[ m273:0 (s421:0 s428:0 s441:0) ]
)when When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ \$l\n\}\n\nWhen\ when\ /rect/\ points\ /direction/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ 1\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /rect/\ points\ /direction/\ with\ length\ /l/\ \{\n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n\}\n with environment {{this builtin-programs/points-at.folk}}
when #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2) (
[ m274:0 (s430:0) ]
)when #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2).\n\nif\ \{\$::tcl_platform(os)\ ne\ \"linux\"\}\ \{\ return\ \}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/camera/usb.folk}}
when When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ (
[ m276:0 (s426:0 s432:0) ]
)when When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{\$tag\ >=\ 48600\}\ \{\ return\ \}\n\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ has\ a\ program\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ is\ a\ tag\n\}\n\nWhen\ -noncapturing\ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/programs.folk}}
when tag /tag/ has detection /any/ on camera /any/ at timestamp /any/ {
# Setting aside this tag (
[ m27427:1067 () ]
[ m27438:1067 () ]
[ m27483:1062 () ]
[ m27504:1066 () ]
[ m27516:1066 () ]
[ m27543:1063 () ]
[ m27565:1067 () ]
[ m27588:1066 () ]
[ m27637:1067 () ]
[ m27650:1052 () ]
[ m27675:1066 () ]
[ m27697:1065 () ]
[ m27727:1053 (s53203:1174 s53205:1173) ]
[ m27782:1053 (s14325:857 s14327:865) ]
[ m27796:1053 (s64446:1262 s64448:1262) ]
[ m27834:1053 (s15535:766 s15536:765) ]
)when tag /tag/ has detection /any/ on camera /any/ at timestamp /any/ {
# Setting aside this tag space (48600 to 48713) for calibration.
if {$tag >= 48600} { return }
Claim -keep 100ms tag $tag has a program
Claim -keep 100ms tag $tag is a tag
} with environment {{this builtin-programs/programs.folk} {} {}}
when tag /tag/ has detection /any/ on camera /any/ at timestamp /timestamp/ {
# Setting aside thi (
[ m27266:1067 () ]
[ m27305:1067 () ]
[ m27322:1067 () ]
[ m27355:1066 () ]
[ m27382:1067 () ]
[ m27426:1067 () ]
[ m27453:1066 () ]
[ m27502:1067 () ]
[ m27518:1065 () ]
[ m27542:1067 () ]
[ m27563:1067 () ]
[ m27586:1067 () ]
[ m27618:1066 () ]
[ m27636:1064 () ]
[ m27674:1052 () ]
[ m27696:1053 () ]
[ m27725:1067 (s52869:1153) ]
[ m27795:1067 (s64447:987) ]
[ m27833:1060 (s31836:1146) ]
)when tag /tag/ has detection /any/ on camera /any/ at timestamp /timestamp/ {
# Setting aside this tag space (48600 to 48713) for calibration.
if {!($tag >= 0 && $tag < 48600)} { return }
Wish -keep 100ms $tag has resolved geometry
} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when tag /tag/ has detection /det/ on camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-in (
[ m27371:1065 () ]
[ m27428:1067 () ]
[ m27478:1066 () ]
[ m27505:1065 () ]
[ m27507:1066 () ]
[ m27520:1061 () ]
[ m27544:1067 () ]
[ m27566:1067 () ]
[ m27621:1064 () ]
[ m27638:1066 () ]
[ m27676:1066 () ]
[ m27694:1067 (s9458:1266) ]
[ m27698:1067 () ]
[ m27729:1053 (s9498:1266) ]
[ m27798:1067 (s9577:1261) ]
[ m27835:1067 (s9619:1265) ]
)when tag /tag/ has detection /det/ on camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 at timestamp /timestamp/ {When {$tag} has resolved geometry /geom/ \n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ } with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {} {cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {unfreezeThresholdSq 0.0001 unfreezeLength 0.3 unfreezeThreshold 0.01}}
when tag /any/ has a program {
$collectLib ScheduleRecollect! $pattern $settleNs
On u (
[ m48150:643 () ]
[ m33949:727 () ]
[ m6520:986 () ]
[ m6714:990 () ]
[ m3413:1024 () ]
[ m47704:1063 () ]
)when tag /any/ has a program {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {tag /any/ has a program} settle 0ms} {settleMs 0 settleNs 0}}
when tag /id/ has quad /q/ \n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ (
[ m27705:1058 (s9474:1265) ]
[ m27784:1067 (s9561:1266) ]
[ m27819:1053 (s9600:1262) ]
)when tag /id/ has quad /q/ \n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {proj monitor projWidth 4096 projHeight 2160} {} {projectorIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when tag 11 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m26280:1065 () ]
[ m26409:1067 () ]
[ m26621:1067 () ]
[ m26761:1067 () ]
[ m26990:1063 () ]
[ m27485:1061 () ]
[ m27626:1067 () ]
)when tag 11 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 11 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when tag 82 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m26837:1058 () ]
[ m26930:1067 () ]
[ m27234:1066 () ]
[ m27388:1067 () ]
[ m27514:1065 () ]
[ m27701:1058 (s9467:1265) ]
[ m27851:1053 () ]
)when tag 82 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 82 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}} {}}
when tag 62 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m27052:1067 () ]
[ m27331:1067 () ]
[ m27513:1066 () ]
[ m27643:1066 () ]
[ m27803:1067 (s9584:1261) ]
)when tag 62 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 62 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when tag 63 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m27360:1064 () ]
[ m27569:1067 () ]
[ m27678:1064 () ]
[ m27838:1053 (s9623:1266) ]
)when tag 63 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 63 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when tag 54-frame-6 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-6 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-6 geom {width 0.1055 height 0.0695}} {}}
when tag 54-frame-5 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-5 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-5 geom {width 0.1055 height 0.0695}} {}}
when tag 54-frame-4 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-4 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-4 geom {width 0.1055 height 0.0695}} {}}
when tag 54-frame-3 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-3 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-3 geom {width 0.1055 height 0.0695}} {}}
when tag 54-frame-2 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-2 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-2 geom {width 0.1055 height 0.0695}} {}}
when tag 54-frame-1 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-frame-1 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-frame-1 geom {width 0.1055 height 0.0695}} {}}
when tag 54-display has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ ()when tag 54-display has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54-display geom {width 0.1055 height 0.0695}} {}}
when tag 54 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m25997:1062 () ]
[ m26377:1065 () ]
[ m26463:1066 () ]
[ m26848:1061 () ]
[ m27019:1066 () ]
[ m27394:1066 () ]
[ m27529:1067 () ]
[ m27703:1067 () ]
)when tag 54 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 54 geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {}}
when tag 83 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ (
[ m26873:1067 () ]
[ m26977:1067 () ]
[ m27220:1067 () ]
[ m27275:1067 () ]
[ m27434:1067 () ]
[ m27556:1067 () ]
[ m27740:1063 (s9510:1266) ]
)when tag 83 has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {tag 83 geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}} {}}
when /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int( (
[ m286:0 (s445:0 s447:0) ]
[ m340:0 (s532:0 s537:0) ]
[ m59909:19 () ]
)when /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
} with environment {{this builtin-programs/errors.folk} {} {}}
when /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int( ()when /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
} with environment {{this builtin-programs/errors.folk} {} {}}
when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /some (
[ m23606:0 (s31272:0) ]
[ m25697:914 (s2833:1077) ]
[ m6706:990 (s53265:1175) ]
[ m6741:979 (s53303:1172) ]
[ m3080:1024 (s31871:1202) ]
[ m44670:1033 (s51873:1209) ]
[ m23363:1061 (s14692:1260) ]
[ m47764:1057 (s64533:1262) ]
)when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /some (
[ m23604:0 (s31270:0) ]
[ m25689:915 (s2826:1086) ]
[ m6701:989 (s53260:1174) ]
[ m6735:989 (s53297:1175) ]
[ m3077:1024 (s31868:1203) ]
[ m44666:1039 (s51865:1231) ]
[ m23361:1040 (s14690:1260) ]
[ m47749:1058 (s64518:1262) ]
)when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /some (
[ m23602:0 (s31268:0) ]
[ m25674:915 (s2820:1088) ]
[ m6698:989 (s53254:1173) ]
[ m6728:990 (s53291:1175) ]
[ m3073:1003 (s31863:1214) ]
[ m44662:1033 (s51862:1213) ]
[ m23359:1039 (s14688:1260) ]
[ m47740:1061 (s64510:1262) ]
)when /p/ has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {}}
when /p/ has canvas /writableTexture/ with /...wiOptions/ {When {$p} has canvas projection /surfaceTo (
[ m23600:0 (s31266:0) ]
[ m25670:912 (s2804:1088) ]
[ m6695:989 (s53252:1172) ]
[ m6722:990 (s53281:1175) ]
[ m3068:1024 (s31855:1214) ]
[ m44655:1032 (s51857:1233) ]
[ m23357:1040 (s14686:1260) ]
[ m47735:1064 (s64502:1262) ]
)when /p/ has canvas /writableTexture/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ & /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {}}
when /p/ is a viewport \n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n (
[ m42652:1047 () ]
[ m1781:1052 () ]
[ m43502:1050 () ]
[ m24896:1056 () ]
[ m65118:1057 () ]
[ m47732:1060 (s64494:1262 s64495:1262 s64497:1262) ]
)when /p/ is a viewport \n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n with environment {{this 82} {} {} {id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {}}
when \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ (
[ m292:0 (s459:0 s461:0) ]
)when \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ /r2/\ \{\n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n\}\n\nWhen\ when\ /p/\ has\ neighbor\ /n/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ Wish\ \$p\ has\ neighbors\n\}\n with environment {{this builtin-programs/intersect.folk}}
when {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1 (
[ m308:0 (s491:0 s498:0) ]
)when {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1/ has region /r1/ & /p2/ has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}
When /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
}
} with environment {{this builtin-programs/regions.folk}}
when {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([str (
[ m316:0 (s519:0) ]
)when {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
} with environment {{this builtin-programs/terminal-ui.folk}}
when ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumb (
[ m322:0 (s506:0 s512:0) ]
)when ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumbnail\ grid\ with\ 8\ frames\ and\ 4\ columns\n#\ \ \ When\ \$this\ has\ thumbnail\ grid\ /thumbnails/\ \{\n#\ \ \ \ \ Wish\ \$this\ draws\ \$thumbnails\;\ #\ Would\ need\ to\ query\ \$thumnails\ for\ its\ frameCount\ and\ columns\n#\ \ \ \}\n#######\n\n#\ -\ path\ get\ prepended\ with\ ~/folk-images/\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /anyone/\ wishes\ /p/\ draws\ sprite\ /path/\ with\ /...options/\ \{\n\n\ \ set\ frames\ \[dict\ get\ \$options\ frames\]\n\ \ set\ columns\ \[dict\ get\ \$options\ columns\]\n\ \ set\ fps\ \[dict\ getdef\ \$options\ fps\ 60\]\n\n\ \ fn\ loadImage\n\ \ set\ im\ \[loadImage\ \$path\]\n\n\ \ set\ sheetWidth\ \[\$imageLib\ Image_width\ \$im\]\n\ \ set\ sheetHeight\ \[\$imageLib\ Image_height\ \$im\]\n\ \ set\ spriteWidth\ \[/\ \$sheetWidth\ \$columns\]\n\ \ set\ rows\ \[/\ \$frames\ \$columns\]\n\ \ set\ spriteHeight\ \[/\ \$sheetHeight\ \$rows\]\n\n\ \ When\ -atomicallyWithKey\ \[list\ sprite\ \$p\ \$path\]\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ set\ frameNumber\ \[expr\ \{round\ (\$t\ *\ \$fps)\ %\ \$frames\}\]\n\ \ \ \ \ \ set\ x\ \[expr\ \{(\$frameNumber\ %\ \$columns)\ *\ \$spriteWidth\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{(\$frameNumber\ %\ \$rows)\ *\ \$spriteHeight\}\]\n\n\ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$im\ \$x\ \$y\ \$spriteWidth\ \$spriteHeight\]\n\ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$subimage\ with\ \{*\}\$options\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ Wish\ \$this\ draws\ sprite\ \$path\ with\ 8\ frames\ and\ 4\ columns\n\}\n with environment {{this builtin-programs/sprites.folk}}
when When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ & (
[ m323:0 (s510:0) ]
)when When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\n\ \ \ \ fn\ printProgram\ \{printer\ id\ code\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ writeFolkFile\ \$id\ \$code\n\ \ \ \ \ \ \ \ writeMetaFile\ \$printer\ \$id\n\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ is\ at\ /address/\n\ \ \ \ \ \ \ \ set\ printerSocket\ \[socket\ stream\ \$\{address\}:9100\]\n\n\ \ \ \ \ \ \ \ fconfigure\ \$printerSocket\ -translation\ binary\ -buffering\ none\n\ \ \ \ \ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[init\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[tag\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\])\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 2\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[cut\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$printerSocket\ \[render\ \$template\]\n\ \ \ \ \ \ \ \ close\ \$printerSocket\n\ \ \ \ \}\n\n\ \ \ \ fn\ render\ \{template\}\ \{\n\ \ \ \ \ \ \ \ set\ trimmed\ \[lmap\ line\ \[split\ \$template\ \"\\n\"\]\ \{\ string\ trim\ \$line\ \}\]\n\ \ \ \ \ \ \ \ set\ singleLine\ \[join\ \$trimmed\ \"\"\]\n\ \ \ \ \ \ \ \ return\ \[uplevel\ \[list\ subst\ \$singleLine\]\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeFolkFile\ \{id\ code\}\ \{\n\ \ \ \ \ \ \ \ set\ folkFile\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$folkFile\ \$code\n\ \ \ \ \ \ \ \ close\ \$folkFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeMetaFile\ \{printer\ id\}\ \{\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ has\ tag\ geometry\ /geometry/\n\ \ \ \ \ \ \ \ set\ metaFile\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$metaFile\ \[subst\ \{Claim\ tag\ \\\$this\ has\ geometry\ \{\$geometry\}\}\]\n\ \ \ \ \ \ \ \ close\ \$metaFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ cut\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1dV\\x0\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ feed\ n\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"\\x1b\\x64%c\"\ \$n\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ init\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1b\\x40\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ raw\ number\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"%c\"\ \$number\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ scaledAprilTag\ \{id\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ \ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\ \}\ \{\$i\ <\ \$scale\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \[expr\ \{\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ !=\ 255\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \{*\}\[lrepeat\ \$scale\ \$bit\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$tagBits\n\ \ \ \ \}\n\n\ \ \ \ #\ scale\ must\ be\ divisible\ by\ 4\ so\ width\ will\ be\ divisible\ by\ 8\n\ \ \ \ fn\ tag\ \{id\ \{scale\ 12\}\}\ \{\n\ \ \ \ \ \ \ \ set\ tagBits\ \[scaledAprilTag\ \$id\ \$scale\]\n\n\ \ \ \ \ \ \ \ set\ width\ \[expr\ \{10\ *\ \$scale\}\]\n\ \ \ \ \ \ \ \ set\ xL\ \[expr\ \{\$width\ /\ 8\}\]\ \ \ \;#\ width\ in\ bytes\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yL\ \[expr\ \{\$width\ %\ 256\}\]\ \;#\ height\ in\ lines\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yH\ \[expr\ \{\$width\ /\ 256\}\]\ \;#\ height\ in\ lines\ (high\ byte)\n\n\ \ \ \ \ \ \ \ return\ \"\\x1dv0\\x03\[raw\ \$xL\]\\x00\[raw\ \$yL\]\[raw\ \$yH\]\[binary\ format\ B*\ \[join\ \$tagBits\ \"\"\]\]\"\n\ \ \ \ \}\n\n\ \ \ \ Subscribe:\ print\ program\ /id/\ on\ receipt\ printer\ /printer/\ with\ code\ /code/\ \{\n\ \ \ \ \ \ \ \ printProgram\ \$printer\ \$id\ \$code\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/esc-pos.folk}}
when When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apri (
[ m326:0 (s511:0) ]
)when When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n\}\n with environment {{this builtin-programs/apriltags.folk}}
when #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ (
[ m331:0 (s1407:0 s1408:0 s1409:0 s1410:0 s1411:0 s1412:0) ]
)when #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ \ \ set\ properties\ \[exec\ udevadm\ info\ --query=property\ --name=\$device\]\n\ \ \ \ if\ \{\$properties\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ false\n\ \ \ \ \}\n\ \ \ \ set\ isKeyboard\ \[string\ match\ *ID_INPUT_KEYBOARD=1*\ \$properties\]\n\ \ \ \ return\ \$isKeyboard\n\ \ \ \ #\ TODO:\ Excluding\ mice\ would\ nice\ to\ keey\ the\ list\ of\ keyboard\ devices\ short\n\ \ \ \ #\ \ \ \ \ \ \ Alas,\ including\ mice\ is\ necessary\ for\ the\ Logitech\ K400R\ keyboard\n\ \ \ \ #\ set\ isMouse\ \[string\ match\ *ID_INPUT_MOUSE=1*\ \$properties\]\n\ \ \ \ #\ return\ \[expr\ \{\$isKeyboard\ &&\ !\$isMouse\}\]\n\}\n\n####\n#\ /dev/input/event*\ addresses\ are\ the\ ground\ truth\ for\ keyboard\ devices\n#\n#\ This\ function\ goes\ through\ each\ of\ them\ and\ checks\ if\ they\ are\ keyboards\nproc\ walkInputEventPaths\ \{\}\ \{\n\ \ \ \ #\ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/event*\"\]\n\ \ \ \ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/by-path/*\"\]\n\ \ \ \ set\ keyboards\ \[list\]\n\ \ \ \ foreach\ device\ \$allDevices\ \{\n\ \ \ \ \ \ \ \ if\ \{\[isKeyboard\ \$device\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[file\ readable\ \$device\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"keyboard:\ Device\ \$device\ is\ not\ readable.\ Attempting\ to\ change\ permissions.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Attempt\ to\ change\ permissions\ so\ that\ the\ file\ can\ be\ read\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ chmod\ +r\ \$device\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ keyboards\ \$device\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$keyboards\n\}\n\nset\ keyboardDevices\ \[walkInputEventPaths\]\nforeach\ keyboard\ \$keyboardDevices\ \{\n\ \ \ \ Claim\ \$keyboard\ is\ a\ keyboard\ device\n\}\n\n#\ backwards\ compatibility\nWhen\ /page/\ is\ a\ keyboard\ with\ path\ /keyboard/\ \{\n\ \ \ \ Claim\ \$page\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ us\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ device\ \{\n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/keyboard.folk}}
when set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octag (
[ m341:0 (s536:0 s543:0 s548:0 s558:0 s562:0 s570:0 s574:0 s581:0 s584:0 s590:0 s595:0 s600:0) ]
)when set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octagon\ 8\ nonagon\ 9\]\n\nproc\ process_offset\ \{offset\ region\}\ \{\n\ \ if\ \{!\[info\ exists\ region\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ set\ w\ \[region\ width\ \$region\]\n\ \ set\ h\ \[region\ height\ \$region\]\n\ \ \n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \n\ \ \ \ \ \ !\[string\ match\ *%*\ \$offset\]\ &&\ \n\ \ \ \ \ \ !\[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ simple\ percentage\ string:\ \"50%\"\n\ \ if\ \{\[string\ match\ *%*\ \$offset\]\ &&\ \[llength\ \$offset\]\ ==\ 1\}\ \{\n\ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$offset\]\ /\ 100.0\}\]\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \ #\ Default\ to\ horizontal\ offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ strings:\ \"right\",\ \"left\",\ \"up\",\ \"down\"\n\ \ if\ \{\$offset\ eq\ \"right\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"left\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{-\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"up\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ 0.5\}\]\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"down\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{\$h\ *\ 0.5\}\]\]\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ percentage:\ \"right\ 50%\",\ \"left\ 25%\",\ etc.\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ set\ direction\ \[lindex\ \$offset\ 0\]\n\ \ \ \ set\ amount\ \[lindex\ \$offset\ 1\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$amount\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$amount\]\ /\ 100.0\}\]\n\n\ \ \ \ \ \ switch\ \$direction\ \{\n\ \ \ \ \ \ \ \ \"right\"\ \{\ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"left\"\ \ \{\ return\ \[list\ \[expr\ \{-\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"up\"\ \ \ \ \{\ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ \"down\"\ \ \{\ return\ \[list\ 0\ \[expr\ \{\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ default\ \{\ return\ \[list\ 0\ 0\]\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\ \ \n\ \ #\ Handle\ x\ y\ vector\ where\ one\ or\ both\ components\ have\ percentage\ notation\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\}\ \{\n\ \ \ \ lassign\ \$offset\ ox\ oy\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$ox\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$ox\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ ox\ \[expr\ \{\$w\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$oy\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$oy\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ oy\ \[expr\ \{\$h\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ \[list\ \$ox\ \$oy\]\n\ \ \}\n\ \ \n\ \ #\ Default\ fallback\n\ \ return\ \$offset\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ shape\ with\ /...options/\ \{\n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ color\ white\n\}\n\n#\ Handle\ \"a\"\ vs\ \"an\"\ grammar\ variations\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n\}\ \n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ \{\n\ \ \ \ Wish\ \$p\ draws\ text\ \$text\ with\ color\ white\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\n#\ Pass\ through\ options\ for\ \"an\"\ version\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ with\ /...options/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ \{*\}\$options\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ rect\ with\ width\ /w/\ height\ /h/\ \{\n\ \ Wish\ \$p\ draws\ a\ rect\ with\ width\ \$w\ height\ \$h\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ radius\ /rad/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ radius\ \$rad\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ set\ of\ points\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ polyline\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ Center\ circle\n\ \ Wish\ \$this\ draws\ a\ circle\n\ \ \n\ \ #\ Grid\ of\ shapes\ with\ varying\ thickness\n\ \ set\ baseX\ -850\n\ \ set\ baseY\ -200\n\ \ set\ gridSpacing\ 130\n\n\ \ #\ Row\ 0:\ Title\n\ \ Wish\ \$this\ draws\ text\ \"triangle\"\ with\ color\ skyblue\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"square\"\ with\ color\ green\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"pentagon\"\ with\ color\ gold\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"hexagon\"\ with\ color\ orange\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ \n\ \ #\ Row\ 1:\ Regular\ polygons\ with\ different\ colors\ and\ thickness\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ thickness\ 2\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ thickness\ 4\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ thickness\ 6\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ thickness\ 8\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ \n\ \ #\ Row\ 2:\ Filled\ shapes\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ filled\ true\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\n\ \ #\ Row\ 3:\ Directional\ offset\ examples\ (replacing\ shift)\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ radius\ 40\ offset\ \"right\ 50%\"\ color\ skyblue\n\ \ Wish\ \$this\ draws\ a\ square\ with\ radius\ 40\ offset\ \ \"left\ 50%\"\ color\ green\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ radius\ 40\ offset\ \"up\ 50%\"\ color\ gold\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ radius\ 40\ offset\ \"down\ 50%\"\ color\ orange\n\ \ \n\ \ #\ Row\ 4:\ Rectangles\ with\ different\ properties\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ cyan\ thickness\ 3\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ magenta\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \"right\ 50%\"\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \ \"left\ 50%\"\n\ \ \n#\ Animated\ elements\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ angle\ \$r\]\ angle\n\ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 8\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ offsetVector\ \[list\ \[sin\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\ \[*\ 2\ \[cos\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\]\]\n\ \ \ \ \ \ \ \ \ \ set\ vector\ \[::vec2::scale\ \$offsetVector\ \[+\ \[*\ \$i\ \$i\]\ 15\]\]\n\ \ \ \ \ \ \ \ \ \ Wish\ \$this\ draws\ a\ circle\ with\ radius\ \$i\ color\ palegoldenrod\ offset\ \$vector\n\ \ \ \ \ \ \}\n\ \ \}\n\ \ \n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(sin(\$t)\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[-\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[-\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fillVal\"\ color\ red\n\ \ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(\$t\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[+\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[+\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fill\"\ color\ red\n\ \ \}\n\ \ \n\ \ Wish\ \$this\ is\ outlined\ white\n\}\n with environment {{this builtin-programs/shapes.folk}}
when #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n# (
[ m352:0 (s1436:3 s1437:3) ]
)when #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n#\ ALSA,\ PulseAudio,\ or\ JACK\ drivers.\n#\n#\ See\ https://miniaud.io/.\ We\ are\ using\ Miniaudio\ v0.11.23.\n#\n#\ Examples:\n#\n#\ Play\ a\ sound\ file\ in\ assets/sounds/\ or\ user-programs/\$hostname/sounds:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ drums.wav\n#\n#\ Play\ a\ sound\ file\ by\ absolute\ path:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ /home/folk/sounds/drums.wav\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/miniaudio\n\nif\ \{!\[catch\ \{exec\ which\ sclang\}\]\}\ \{\n\ \ \ \ #\ HACK:\ We're\ running\ msuic.folk\ and\ therefore\ are\ running\ JACK,\n\ \ \ \ #\ so\ we\ should\ force\ miniaudio\ to\ not\ use\ ALSA\ directly\ (because\n\ \ \ \ #\ that\ won't\ work).\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ MA_NO_ALSA\n\ \ \ \ \ \ \ \ #define\ MA_NO_PULSEAUDIO\n\ \ \ \ \}\n\}\n\$cc\ code\ \{\n\ \ \ #define\ MINIAUDIO_IMPLEMENTATION\n\}\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <stdint.h>\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <miniaudio.h>\n\nif\ \{\$::tcl_platform(os)\ ne\ \"Darwin\"\}\ \{\n\ \ \ \ \$cc\ endcflags\ -lpthread\ -lm\ -ldl\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ ma_context\ \ \ \ \ g_ctx\;\n\ \ \ \ static\ ma_engine\ \ \ \ \ \ g_engine\;\n\ \ \ \ static\ ma_sound_group\ g_group\;\n\n\ \ \ \ static\ bool\ g_ctx_initialized\ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_engine_initialized\ =\ false\;\n\ \ \ \ static\ bool\ g_engine_started\ \ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_group_initialized\ \ =\ false\;\n\n\ \ \ \ static\ pthread_mutex_t\ g_state_mtx\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ typedef\ struct\ SoundNode\ \{\n\ \ \ \ \ \ \ \ ma_sound*\ \ \ \ \ \ \ \ \ snd\;\n\ \ \ \ \ \ \ \ struct\ SoundNode*\ next\;\n\ \ \ \ \}\ SoundNode\;\n\n\ \ \ \ static\ SoundNode*\ \ \ \ \ \ g_head\ \ \ \ \ \ \ \ \ \ \ \ =\ NULL\;\n\ \ \ \ static\ pthread_mutex_t\ g_list_mtx\ \ \ \ \ \ \ \ =\ PTHREAD_MUTEX_INITIALIZER\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ \ =\ false\;\n\ \ \ \ static\ pthread_t\ \ \ \ \ \ \ g_reaper_thr\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ /*\ Maintains\ linked\ list\ of\ active\ sounds\ */\n\ \ \ \ static\ bool\ registry_add(ma_sound*\ snd)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ (SoundNode*)malloc(sizeof\ *node)\;\n\n\ \ \ \ \ \ \ \ if\ (!node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ registry_add:\ alloc\ failed\\n\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ node->snd\ =\ snd\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ node->next\ =\ g_head\;\n\ \ \ \ \ \ \ \ g_head\ =\ node\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Removes\ and\ uninitializes\ all\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void\ registry_clear_locked(void)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ next\ =\ node->next\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (node->snd)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(node)\;\n\ \ \ \ \ \ \ \ \ \ \ \ node\ =\ next\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ g_head\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Background\ thread\ that\ periodically\ removes\ finished\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void*\ reaper_main(void*\ arg)\ \{\n\ \ \ \ \ \ \ \ (void)arg\;\n\n\ \ \ \ \ \ \ \ while\ (!g_shutdown_reaper)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ \ node\ \ =\ g_head\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound*\ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ remove\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (snd\ &&\ !ma_sound_is_playing(snd)\ &&\ !ma_sound_is_looping(snd))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Collect\ finished\ sounds\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remove\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (remove)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(to_free)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ usleep(50\ *\ 1000)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ registry_clear_locked()\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ g_reaper_running\ =\ false\;\n\ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ static\ int\ reaper_start(void)\ \{\n\ \ \ \ \ \ \ \ if\ (g_reaper_running)\ return\ 0\;\n\ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ \ \ \ \ int\ err\ =\ pthread_create(&g_reaper_thr,\ NULL,\ reaper_main,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (err\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ err\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Initializes\ the\ audio\ backend\ and\ sound\ group,\ and\ starts\ the\ reaper\ thread\ */\n\ \ \ \ static\ bool\ audio_init_impl(void)\ \{\n\ \ \ \ \ \ \ \ ma_result\ r\;\n\n\ \ \ \ \ \ \ \ if\ (!g_ctx_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_context_init(NULL,\ 0,\ NULL,\ &g_ctx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ context\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_ctx_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ma_engine_config\ cfg\ =\ ma_engine_config_init()\;\n\ \ \ \ \ \ \ \ \ \ \ \ cfg.pContext\ =\ &g_ctx\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_init(&cfg,\ &g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"miniaudio:\ engine\ initialized\ with\ %s\ backend\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_get_backend_name(g_ctx.backend))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_started)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_start(&g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ start\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_group_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_sound_group_init(&g_engine,\ 0,\ NULL,\ &g_group)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ group\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Unwind\ engine\ on\ group\ failure\;\ context\ remains\ for\ future\ attempts\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_engine_uninit(&g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memset(&g_engine,\ 0,\ sizeof\ g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_group_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ err\ =\ reaper_start()\;\n\n\ \ \ \ \ \ \ \ if\ (err\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"audio:\ reaper\ thread\ create\ failed:\ %d\\n\",\ err)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ audioInit\ \{\}\ bool\ \{\n\ \ \ \ pthread_mutex_lock(&g_state_mtx)\;\n\ \ \ \ bool\ success\ =\ audio_init_impl()\;\n\ \ \ \ pthread_mutex_unlock(&g_state_mtx)\;\n\n\ \ \ \ if\ (success)\ \{\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ERROR(\"miniaudio:\ audio\ init\ failed\\n\")\;\n\ \ \ \ return\ false\;\n\}\n\n\$cc\ proc\ audioStop\ \{ma_sound*\ target\}\ void\ \{\n\ \ \ \ SoundNode*\ to_free\ =\ NULL\;\n\ \ \ \ ma_sound*\ snd\ =\ NULL\;\n\n\ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ /*\ Find\ the\ sound\ to\ stop.\ TODO:\ this\ duplicates\ traversal\ logic\ from\ the\ reaper\ thread\ */\n\ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ if\ (node->snd\ ==\ target)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ node->snd\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ /*\ Sound\ already\ reaped\ or\ never\ registered\ */\n\ \ \ \ if\ (!to_free)\ return\;\n\n\ \ \ \ if\ (snd)\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ snd\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ free(to_free)\;\n\}\n\n\$cc\ proc\ playSound\ \{char*\ path\}\ ma_sound*\ \{\n\ \ \ \ ma_sound*\ snd\ =\ (ma_sound*)malloc(sizeof\ *snd)\;\n\n\ \ \ \ if\ (!snd)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ alloc\ sound\ failed\\n\")\;\n\ \ \ \ \}\n\n\ \ \ \ ma_result\ r\ =\ ma_sound_init_from_file(&g_engine,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MA_SOUND_FLAG_DECODE\ |\ MA_SOUND_FLAG_NO_SPATIALIZATION,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &g_group,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ init\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ r\ =\ ma_sound_start(snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ start\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (!registry_add(snd))\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ registry\ add\ failed\ for\ %s\\n\",\ path)\;\n\ \ \ \ \}\n\n\ \ \ \ fprintf(stderr,\ \"miniaudio:\ playing\ %s\\n\",\ path)\;\n\ \ \ \ return\ snd\;\n\}\n\ntry\ \{\n\ \ \ \ set\ audioLib\ \[\$cc\ compile\]\n\ \ \ \ set\ success\ \[\$audioLib\ audioInit\]\n\n\ \ \ \ if\ \{!\$success\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ init\ failed\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ audio\ library\ is\ \$audioLib\n\}\ on\ error\ e\ \{\n\ \ \ \ puts\ stderr\ \"audio:\ compile\ failed:\ \$e\"\n\}\n\nWhen\ the\ audio\ library\ is\ /audioLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ play\ audio\ /sound/\ \{\n\n\ \ \ \ #\ Check\ if\ the\ sound\ file\ exists\ in\ the\ user-programs/\$hostname/sounds\ directory\n\ \ \ \ #\ or\ in\ the\ working\ directory's\ assets/sounds\ subdirectory.\ Otherwise,\ assume\n\ \ \ \ #\ it's\ an\ absolute\ path.\n\ \ \ \ proc\ resolveSoundPath\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ scriptDir\ \[file\ dirname\ \[info\ script\]\]\n\ \ \ \ \ \ \ \ set\ projectRoot\ \[pwd\]\n\ \ \ \ \ \ \ \ set\ hostname\ \[info\ hostname\]\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/user-programs/\$hostname/audio/\$filename\"\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/audio/\$filename\"\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ #\ treat\ as\ an\ absolute\ path\n\ \ \ \ \ \ \ \ return\ \$filename\n\ \ \ \ \}\n\n\ \ \ \ set\ path\ \[resolveSoundPath\ \$sound\]\n\n\ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ File\ not\ found\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ handle\ \[\$audioLib\ playSound\ \$path\]\n\n\ \ \ \ if\ \{\$handle\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ Failed\ to\ play\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ puts\ \"audio:\ stopping\ audio\ '\$path'\"\n\ \ \ \ \ \ \ \ \$audioLib\ audioStop\ \$handle\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/audio.folk}}
when #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{ (
[ m354:0 (s563:0 s567:0 s571:0) ]
)when #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{\n#\ \ \ \ \ Wish\ \$this\ displays\ camera\ slice\ \$slice\n#\ \}\n\n#\ Callback:\ extract\ out\ a\ camera\ slice\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ camera\ slice\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ intrinsics\ /cameraIntrinsics/\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ frame\ /frame/\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ /p/\ has\ quad\ /q/\ \{\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n\}\n\n#\ Auto-trigger\ callback\ for\ `when\ has\ camera\ slice`\ statements\nWhen\ when\ /p/\ has\ camera\ slice\ /slice/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ -nonatomically\ \$p\ has\ camera\ slice\n\}\n\n#\ Display\ a\ camera\ slice\ (for\ backward\ compatibility).\nWhen\ /someone/\ wishes\ /p/\ displays\ camera\ slice\ /slice/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$slice\n\}\n with environment {{this builtin-programs/camera/slice.folk}}
when When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWi (
[ m356:0 (s569:0) ]
)when When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/tags-to-quads.folk}}
when #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ title (
[ m364:0 (s572:0 s580:0) ]
)when #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ titled\ \"This\ is\ a\ tag\"\n#\ Wish\ \$this\ is\ footnoted\ \"This\ is\ a\ footnote\"\n#\ Wish\ \$this\ is\ right-margined\ \"This\ is\ right-margined\ text\"\n#\ Wish\ \$this\ is\ left-margined\ \"This\ is\ left-margined\ text\"\n\nWhen\ /thing/\ has\ quad\ /quad/\ \{\n\ \ \ \ Claim\ -keep\ 50ms\ \$thing\ has\ a\ quad\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /thing/\ has\ a\ quad\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/title.folk}}
when When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ (
[ m365:0 (s628:0 s629:0) ]
)when When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ scaled\ by\ x\ /xScale/\ y\ /yScale/\ \{\n\ \ \ \ proc\ extractMm\ \{mm\}\ \{\n\ \ \ \ \ \ \ \ regexp\ \{(\[0-9.\]+)mm\}\ \$mm\ ->\ extracted\n\ \ \ \ \ \ \ \ return\ \$extracted\n\ \ \ \ \}\n\n\ \ \ \ set\ tagSize\ \[extractMm\ \[dict\ get\ \$defaultGeom\ tagSize\]\]\n\ \ \ \ set\ left\ \[extractMm\ \[dict\ get\ \$defaultGeom\ left\]\]\n\ \ \ \ set\ right\ \[extractMm\ \[dict\ get\ \$defaultGeom\ right\]\]\n\ \ \ \ set\ top\ \[extractMm\ \[dict\ get\ \$defaultGeom\ top\]\]\n\ \ \ \ set\ bottom\ \[extractMm\ \[dict\ get\ \$defaultGeom\ bottom\]\]\n\n\ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\n\ \ \ \ set\ right\ \$(\$right\ +\ (\$width\ *\ \$xScale\ -\ \$width))mm\n\ \ \ \ set\ bottom\ \$(\$bottom\ +\ (\$height\ *\ \$yScale\ -\ \$height))mm\n\n\ \ \ \ set\ newGeom\ \[list\ tagSize\ \$\{tagSize\}mm\ left\ \$\{left\}mm\ right\ \$\{right\}mm\ top\ \$\{top\}mm\ bottom\ \$\{bottom\}mm\]\n\n\ \ \ \ Claim\ tag\ \$program\ has\ geometry\ \$newGeom\n\}\n\nWhen\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /tag/\ has\ resolved\ geometry\ \{\n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/tags-geometry.folk}}
when #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connecte (
[ m366:0 (s694:0 s696:0 s702:0 s704:0) ]
)when #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connected\ to\ \$tag2\"\ or\ \"Wish\ \$tag\ is\ dynamically\ connected\ to\ \$tag2\"\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ dynamically\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ sub\ \$sink\ \$source\]\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ grey\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ set\ c\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 2\ color\ \$color\ layer\ \$layer\n\ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ 30\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\}\n\nset\ speed\ 75\nset\ spacing\ 50\nset\ maxsize\ 25\n\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ normalize\ \[vec2\ sub\ \$sink\ \$source\]\]\n\ \ \ set\ distance\ \[vec2\ distance\ \$sink\ \$source\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\ \n\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ lassign\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\ cx\ cy\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 1\ color\ \$color\ layer\ \$layer\n\ \ \ \n\ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ set\ offset\ \[expr\ \{round(\$t*\$speed)\ %\ \$spacing\}\]\n\ \ \ \ \ set\ count\ \[expr\ \{round(\$distance\ /\ \$spacing)\}\]\n\n\ \ \ \ \ for\ \{set\ p\ \$offset\}\ \{\$p\ <\ \$distance\}\ \{incr\ p\ \$spacing\}\ \{\n\ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$source\ \[vec2\ scale\ \$direction\ \$p\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[expr\ \{min(\$maxsize,\ 0.20*min(\$p,\ \$distance\ -\ \$p))\}\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ \$s\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/connections.folk}}
when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n (
[ m915:0 (s2238:0 s2239:0 s2240:0 s2250:0 s2251:0 s2253:0 s2256:0 s2259:0) ]
)when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/tags-to-quads.folk} {} {}}
when libapriltag has been built with config /configCcWithLibapriltag/ {When the image library is /ima (
[ m936:0 (s1629:0) ]
)when libapriltag has been built with config /configCcWithLibapriltag/ {When the image library is /imageLib/ & the program save directory is /saveDir/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n} with environment {{this builtin-programs/print/print.folk} {} {}}
when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n (
[ m943:0 (s6885:0) ]
)when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n with environment {{this builtin-programs/calibrate/refine.folk} {} {}}
when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n (
[ m953:0 (s6279:0) ]
)when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n with environment {{this builtin-programs/calibrate/matlib.folk} {} {}}
when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n (
[ m954:0 (s2108:0) ]
)when libapriltag has been built with config /configCcWithLibapriltag/ \nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/laser.folk} {} {} {imageLib <C:cfileV8MUaU>} {}}
when /thing/ has quad /quad/ {
Claim -keep 50ms $thing has a quad
} with environment {{this built (
[ m27898:1065 (s28214:1253) ]
[ m27955:1047 (s44017:1261) ]
[ m27997:1066 (s40274:1246) ]
[ m28009:1066 (s14491:1259) ]
[ m28027:1066 (s40569:1195) ]
)when /thing/ has quad /quad/ {
Claim -keep 50ms $thing has a quad
} with environment {{this builtin-programs/title.folk} {} {}}
when /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes (
[ m25752:915 (s2895:1084) ]
[ m6747:978 (s53312:1172) ]
[ m3087:1024 (s31879:1214) ]
[ m44680:1038 (s51881:1224) ]
[ m65093:1057 () ]
[ m23383:1039 (s14727:1256) ]
[ m23388:1040 (s14732:1260) ]
[ m23398:1039 (s14743:1223) ]
[ m23404:1062 (s14750:1259) ]
[ m23409:1062 (s14755:1257) ]
[ m23416:1040 (s14762:1256) ]
[ m23427:1062 (s14774:1223) ]
[ m23479:1060 (s14832:1244) ]
[ m47780:1063 (s64544:1258) ]
)when /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
} with environment {{this builtin-programs/decorations/label.folk} {} {}}
when /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \ (
[ m44346:1038 (s51489:1233 s51497:1233 s51501:1233 s51505:1233) ]
[ m16182:1052 (s40279:1249 s40281:1248 s40283:1247 s40284:1246) ]
[ m16428:1053 (s40573:1247 s40575:1244 s40579:1195 s40581:1193) ]
[ m17864:1058 (s28216:1253 s28219:1238 s28223:1245 s28227:1245) ]
[ m23192:1061 (s14495:1257 s14498:1259 s14501:1258 s14504:1259) ]
[ m23740:1058 () ]
[ m24265:1036 () ]
[ m60517:1063 () ]
[ m29751:1064 () ]
[ m45012:1065 () ]
[ m2097:1067 (s44023:1259 s44032:1262 s44035:1240 s44037:1265) ]
[ m25448:1066 () ]
[ m26207:1064 () ]
[ m27147:1066 () ]
[ m27197:1065 () ]
)when /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {}}
when #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ (
[ m371:0 (s634:0 s638:0) ]
)when #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ Wish\ \$this\ runs\ Unix\ command\ \"journalctl\"\ with\ arguments\ \[list\ \"-f\"\ \"-u\"\ \"folk\"\]\nWhen\ /someone/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ with\ arguments\ /args/\ \{\n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n\}\n\n#\ Convenience\ wrapper\ for\ commands\ without\ arguments\nWhen\ /wisher/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ \{\n\tSay\ \$wisher\ wishes\ \$p\ runs\ Unix\ command\ \$command\ with\ arguments\ \[list\]\n\}\n\n#\ When\ /someone/\ wishes\ /p/\ tests\ Unix\ commands\ \{\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"curl\"\ with\ arguments\ \[list\ \"-fsS\"\ \"http://wttr.in/Baltimore?format='%l:+%C'\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"-sSh\"\ \"/home/folk/folk2\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ping\"\ with\ arguments\ \[list\ \"google.com\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"sh\"\ with\ arguments\ \[list\ \"-c\"\ \"while\ :\;\ do\ date\ +%s.%3N\;\ sleep\ 0.5\;\ done\"\]\n\n#\ \t#\ Test\ error\ handling:\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"/nonexistent/path\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"exec\"\ with\ arguments\ \[list\ \"/dev/null\"\]\n\n#\ \tWhen\ \$p\ has\ Unix\ error\ output\ /errorSummary/\ \{\n#\ \t\tputs\ \"errorSummary:\ \$errorSummary\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$errorSummary\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ red\n#\ \t\}\n\n#\ \tWhen\ \$p\ has\ Unix\ output\ lines\ /outputLines/\ \{\n#\ \t\tputs\ \"outputLines:\ \$outputLines\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$outputLines\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ green\n#\ \t\}\n#\ \} with environment {{this builtin-programs/unix-commands.folk}}
when #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ (
[ m378:0 () ]
)when #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ --recursive\ --event\ Updated\ --event\ Created\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ builtin-programs\ \$::env(HOME)/folk-data/local-program\ \$::env(PWD)/user-programs\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -buffering\ line\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ if\ \{\[gets\ \$fd\ line\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"fswatch:\ fswatch\ failed.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{builtin-programs\\/.*\$\}\ \$line\ changedPath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ changedPath\ \$line\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ changedFilename\ \[file\ tail\ \$changedPath\]\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$changedFilename\ 0\]\ eq\ \".\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$changedFilename\ 0\]\ eq\ \"#\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[file\ extension\ \$changedFilename\]\ ne\ \".folk\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ \"fswatch:\ \$changedPath\ updated,\ ignoring.\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"fswatch:\ \$changedPath\ updated,\ reloading.\"\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$changedPath\ r\]\;\ set\ programCode\ \[read\ \$fp\]\;\ close\ \$fp\n\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 100ms\ -on\ boot.folk\ -key\ \[list\ \$changedPath\ code\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$changedPath\ has\ program\ code\ \$programCode\n\ \ \ \ \}\n\}\ on\ error\ err\ \{\n\ \ \ \ puts\ stderr\ \"fswatch:\ Warning:\ could\ not\ invoke\ `fswatch`\ (\$err).\"\n\ \ \ \ puts\ stderr\ \"fswatch:\ Will\ not\ watch\ builtin-programs\ for\ changes.\"\n\}\n with environment {{this builtin-programs/fswatch.folk}}
when {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <u (
[ m388:0 (s1185:0 s1186:0) ]
)when {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <unistd.h>
$cc include <sys/ioctl.h>
$cc include <linux/videodev2.h>
$cc proc getInfoForCamera {char* camera} Jim_Obj* {
int fd = open(camera, O_RDWR);
FOLK_ENSURE(fd >= 0);
Jim_Obj *infoObj = Jim_NewDictObj(interp, NULL, 0);
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "card", -1),
Jim_NewStringObj(interp, (const char *)cap.card, -1));
}
Jim_Obj *formatsList = Jim_NewListObj(interp, NULL, 0);
// Enumerate pixel formats
struct v4l2_fmtdesc fmt_desc = {0};
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
char fourcc_str[5];
fourcc_str[0] = fmt_desc.pixelformat & 0xFF;
fourcc_str[1] = (fmt_desc.pixelformat >> 8) & 0xFF;
fourcc_str[2] = (fmt_desc.pixelformat >> 16) & 0xFF;
fourcc_str[3] = (fmt_desc.pixelformat >> 24) & 0xFF;
fourcc_str[4] = '\0';
Jim_Obj *resolutionsList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmsizeenum frm_size = {0};
frm_size.pixel_format = fmt_desc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frm_size) == 0) {
if (frm_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Jim_Obj *frameratesList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmivalenum frm_interval = {0};
frm_interval.pixel_format = fmt_desc.pixelformat;
frm_interval.width = frm_size.discrete.width;
frm_interval.height = frm_size.discrete.height;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval) == 0) {
if (frm_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
double fps = (double)frm_interval.discrete.denominator /
frm_interval.discrete.numerator;
Jim_ListAppendElement(interp, frameratesList, Jim_NewDoubleObj(interp, fps));
} else if (frm_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
double min_fps = (double)frm_interval.stepwise.max.denominator /
frm_interval.stepwise.max.numerator;
double max_fps = (double)frm_interval.stepwise.min.denominator /
frm_interval.stepwise.min.numerator;
Jim_Obj *rangeDict = Jim_ObjPrintf("min %f max %f", min_fps, max_fps);
Jim_ListAppendElement(interp, frameratesList, rangeDict);
}
frm_interval.index++;
}
int frameratesLen;
const char *frameratesStr = Jim_GetString(frameratesList, &frameratesLen);
Jim_Obj *resDict = Jim_ObjPrintf("width %u height %u framerates {%s}",
frm_size.discrete.width,
frm_size.discrete.height,
frameratesStr);
Jim_ListAppendElement(interp, resolutionsList, resDict);
}
frm_size.index++;
}
int resolutionsLen;
const char *resolutionsStr = Jim_GetString(resolutionsList, &resolutionsLen);
Jim_Obj *formatDict = Jim_ObjPrintf("fourcc {%s} description {%s} resolutions {%s}",
fourcc_str,
(char*)fmt_desc.description,
resolutionsStr);
Jim_ListAppendElement(interp, formatsList, formatDict);
fmt_desc.index++;
}
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "formats", -1),
formatsList);
close(fd);
return infoObj;
}
set formatsLib [$cc compile]
set camerasByCanonicalName [dict create]
set cameras [glob -nocomplain "/dev/v4l/by-path/*"]
# sort first so the order (and therefore which dedupe wins) is
# consistent across boots.
set cameras [lsort $cameras]
foreach camera $cameras {
# I would prefer to use by-id, but not all cameras show up in
# by-id (webcam on my Dell laptop does not, for instance).
try {
set canonicalName [file readlink $camera]
} on error e {
set canonicalName $camera
}
if {[dict exists $camerasByCanonicalName $canonicalName]} {
# Skip cameras that we already have by another name, so there
# aren't dupes in the enumeration (in particular, by-path
# often has both -usb- and -usbv2- copies of a camera).
continue
}
dict set camerasByCanonicalName $canonicalName $camera
set info [$formatsLib getInfoForCamera $camera]
Claim $::thisNode has camera $camera with {*}$info
}
} with environment {{this builtin-programs/camera/enumerate.folk}}
when When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ disp (
[ m389:0 (s632:0) ]
)when When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n\}\n with environment {{this builtin-programs/display-saver.folk}}
when When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\ (
[ m392:0 (s613:0 s616:0) ]
)when When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \"/editor-control\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ html\ \{\n<!DOCTYPE\ html>\n<html\ lang=\"en\">\n\ \ \ \ <head>\n\ \ \ \ \ \ \ \ <meta\ charset=\"utf-8\"\ />\n\ \ \ \ \ \ \ \ <title>Editor\ copy/paste</title>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ </head>\n\ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ \ \ \ \ Select\ a\ keyboard:\ <select\ id=\"keyboard-select\"></select>\n\ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"120\"\ rows=\"40\"></textarea>\n\ \ \ \ \ \ \ \ <script>\nconst\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\nconst\ keyboardSelect\ =\ document.querySelector(\"#keyboard-select\")\;\nconst\ textarea\ =\ document.querySelector(\"#code\")\;\n\nvar\ currentKeyboard\ =\ null\;\nvar\ programCode\ =\ \"\"\;\ //\ not\ the\ same\ as\ editor\ code\nvar\ cursorPosition\ =\ \[0,\ 0\]\;\n\n//\ temporarily\ disable\ event\ processing\ after\ sending\ new\ code\ to\ prevent\ recursive\ event\ sends\nvar\ allowLocalEventsToProcess\ =\ true\;\nvar\ allowRemoteEventsToProcess\ =\ true\;\nvar\ _remoteTimoutHandle\;\nvar\ _localTimeoutHandle\;\nfunction\ disableRemoteEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_remoteTimoutHandle)\ clearTimeout(_remoteTimoutHandle)\;\n\ \ \ \ allowRemoteEventsToProcess\ =\ false\;\n\n\ \ \ \ _remoteTimoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowRemoteEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ disableLocalEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_localTimeoutHandle)\ clearTimeout(_localTimeoutHandle)\;\n\ \ \ \ allowLocalEventsToProcess\ =\ false\;\n\n\ \ \ \ _localTimeoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowLocalEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ updateProgramCode()\ \{\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ currentCode\ =\ textarea.value\;\n\ \ \ \ programCode\ =\ currentCode\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{cursorPosition\[0\]\}\ \$\{cursorPosition\[1\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\nfunction\ updateCursorAndCode(ev)\ \{\n\ \ \ \ if\ (!allowLocalEventsToProcess)\ return\;\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ newCode\ =\ ev.target.value\;\n\n\ \ \ \ //\ figure\ out\ cursor\ position\n\ \ \ \ const\ currentPosition\ =\ textarea.selectionStart\;\n\ \ \ \ const\ linesBefore\ =\ newCode.substring(0,\ currentPosition).split(\"\\n\")\;\n\ \ \ \ const\ y\ =\ linesBefore.length\ -\ 1\;\n\ \ \ \ const\ x\ =\ linesBefore\[linesBefore.length\ -\ 1\].length\;\n\n\ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{x\}\ \$\{y\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(programCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(newCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\ntextarea.addEventListener(\"input\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"selectionchange\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"keydown\",\ ev\ =>\ \{\n\ \ \ \ if(ev.keyCode\ ===\ 83\ /*\ s\ */\ &&\ (navigator.platform.match(\"Mac\")\ ?\ ev.metaKey\ :\ ev.ctrlKey))\ \{\n\ \ \ \ \ \ \ \ ev.preventDefault()\;\n\ \ \ \ \ \ \ \ updateProgramCode()\;\n\ \ \ \ \}\n\})\;\n\nvar\ lastKeyboard\;\ //\ to\ clean\ up\ the\ previous\ keyboard\ when\ another\ is\ picked\nasync\ function\ selectKeyboard(\{\ page,\ kbPath\ \})\ \{\n\ \ \ \ if\ (lastKeyboard)\ lastKeyboard.stop()\;\n\n\ \ \ \ currentKeyboard\ =\ \{\ page,\ kbPath\ \}\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ lastKeyboard\ =\ await\ ws.watch(`\$\{id\}\ has\ base64\ editor\ code\ /editorCode/\ program\ code\ /programCode/\ &\ the\ \$\{kbPath\}\ cursor\ is\ /cursor/`,\ \{\n\ \ \ \ \ \ \ \ add:\ (\{\ editorCode,\ programCode:\ _programCode,\ cursor\ \})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (!allowRemoteEventsToProcess)\ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ disableLocalEventProcessing(500)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ programCode\ =\ atob(_programCode)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ editorCode\ =\ atob(editorCode)\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.value\ =\ editorCode\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ figure\ out\ where\ the\ cursor\ is\n\ \ \ \ \ \ \ \ \ \ \ \ let\ \[x,\ y\]\ =\ loadList(cursor)\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ parseInt(x)\;\ y\ =\ parseInt(y)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ const\ lines\ =\ editorCode.split(\"\\n\")\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ let\ pos\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (let\ i\ =\ 0\;\ i\ <\ y\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ lines\[i\].length\ +\ 1\;\ //\ +\ 1\ for\ newline\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ x\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.focus()\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionStart\ =\ pos\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionEnd\ =\ pos\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \})\;\n\}\n\n//\ update\ keyboard\ list\ as\ it\ changes\nws.watchCollected(\"/page/\ is\ an\ editor\ &\ /page/\ is\ a\ keyboard\ with\ path\ /kbPath/\",\ keyboards\ =>\ \{\n\ \ \ \ keyboardSelect.innerHTML\ =\ \"\"\;\n\n\ \ \ \ for\ (let\ keyboard\ of\ keyboards)\ \{\n\ \ \ \ \ \ \ \ let\ \{page,\ kbPath\}\ =\ keyboard\;\n\ \ \ \ \ \ \ \ keyboardSelect.innerHTML\ +=\ `<option\ value=\"\$\{JSON.stringify(keyboard)\}\">\$\{page\}\ (\$\{kbPath\})</option>`\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (keyboards.length\ ===\ 1)\ \{\n\ \ \ \ \ \ \ \ selectKeyboard(keyboards\[0\])\;\n\ \ \ \ \}\n\})\;\n\n//\ fired\ when\ selected\ keyboard\ changes\nkeyboardSelect.addEventListener(\"input\",\ (ev)\ =>\ \{\n\ \ \ \ selectKeyboard(JSON.parse(ev.target.value))\;\n\})\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ </body>\n</html>\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/editor-control.folk}}
when /page/ has editor code /editorCode/ {When {$page} has program code /programCode/ \n\ \ \ \ Claim ()when /page/ has editor code /editorCode/ {When {$page} has program code /programCode/ \n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n} with environment {{this builtin-programs/editor-control.folk} {} {}}
when /page/ is a keyboard with path /keyboard/ {
Claim $page is a keyboard with path $keyboard lo ()when /page/ is a keyboard with path /keyboard/ {
Claim $page is a keyboard with path $keyboard locale us
} with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}}}
when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd local ()when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd locale /locale/ \n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd} {keyboardChannel ::aio.handle50 KEY_STATES {up down repeat} defaultKeymap {{{1 0} Escape {1 1} Escape {1 2} Escape {1 3} Escape {1 4} Escape {1 5} Escape {1 6} Escape {1 7} Escape {1 8} Meta_Escape {1 9} Meta_Escape {1 10} Meta_Escape {1 11} Meta_Escape {1 12} Meta_Escape {1 13} Meta_Escape {1 14} Meta_Escape {1 15} Meta_Escape {1 16} Escape {1 17} Escape {1 18} Escape {1 19} Escape {1 20} Escape {1 21} Escape {1 22} Escape {1 23} Escape {1 24} Meta_Escape {1 25} Meta_Escape {1 26} Meta_Escape {1 27} Meta_Escape {1 28} Meta_Escape {1 29} Meta_Escape {1 30} Meta_Escape {1 31} Meta_Escape {1 32} Escape {1 33} Escape {1 34} Escape {1 35} Escape {1 36} Escape {1 37} Escape {1 38} Escape {1 39} Escape {1 40} Meta_Escape {1 41} Meta_Escape {1 42} Meta_Escape {1 43} Meta_Escape {1 44} Meta_Escape {1 45} Meta_Escape {1 46} Meta_Escape {1 47} Meta_Escape {1 48} Escape {1 49} Escape {1 50} Escape {1 51} Escape {1 52} Escape {1 53} Escape {1 54} Escape {1 55} Escape {1 56} Meta_Escape {1 57} Meta_Escape {1 58} Meta_Escape {1 59} Meta_Escape {1 60} Meta_Escape {1 61} Meta_Escape {1 62} Meta_Escape {1 63} Meta_Escape {1 64} Escape {1 65} Escape {1 66} Escape {1 67} Escape {1 68} Escape {1 69} Escape {1 70} Escape {1 71} Escape {1 72} Meta_Escape {1 73} Meta_Escape {1 74} Meta_Escape {1 75} Meta_Escape {1 76} Meta_Escape {1 77} Meta_Escape {1 78} Meta_Escape {1 79} Meta_Escape {1 80} Escape {1 81} Escape {1 82} Escape {1 83} Escape {1 84} Escape {1 85} Escape {1 86} Escape {1 87} Escape {1 88} Meta_Escape {1 89} Meta_Escape {1 90} Meta_Escape {1 91} Meta_Escape {1 92} Meta_Escape {1 93} Meta_Escape {1 94} Meta_Escape {1 95} Meta_Escape {1 96} Escape {1 97} Escape {1 98} Escape {1 99} Escape {1 100} Escape {1 101} Escape {1 102} Escape {1 103} Escape {1 104} Meta_Escape {1 105} Meta_Escape {1 106} Meta_Escape {1 107} Meta_Escape {1 108} Meta_Escape {1 109} Meta_Escape {1 110} Meta_Escape {1 111} Meta_Escape {1 112} Escape {1 113} Escape {1 114} Escape {1 115} Escape {1 116} Escape {1 117} Escape {1 118} Escape {1 119} Escape {1 120} Meta_Escape {1 121} Meta_Escape {1 122} Meta_Escape {1 123} Meta_Escape {1 124} Meta_Escape {1 125} Meta_Escape {1 126} Meta_Escape {1 127} Meta_Escape {2 0} one {2 1} exclam {2 2} one {2 3} exclam {2 4} one {2 5} exclam {2 6} one {2 7} exclam {2 8} Meta_one {2 9} Meta_exclam {2 10} Meta_one {2 11} Meta_exclam {2 12} Meta_one {2 13} Meta_exclam {2 14} Meta_one {2 15} Meta_exclam {2 16} one {2 17} exclam {2 18} one {2 19} exclam {2 20} one {2 21} exclam {2 22} one {2 23} exclam {2 24} Meta_one {2 25} Meta_exclam {2 26} Meta_one {2 27} Meta_exclam {2 28} Meta_one {2 29} Meta_exclam {2 30} Meta_one {2 31} Meta_exclam {2 32} one {2 33} exclam {2 34} one {2 35} exclam {2 36} one {2 37} exclam {2 38} one {2 39} exclam {2 40} Meta_one {2 41} Meta_exclam {2 42} Meta_one {2 43} Meta_exclam {2 44} Meta_one {2 45} Meta_exclam {2 46} Meta_one {2 47} Meta_exclam {2 48} one {2 49} exclam {2 50} one {2 51} exclam {2 52} one {2 53} exclam {2 54} one {2 55} exclam {2 56} Meta_one {2 57} Meta_exclam {2 58} Meta_one {2 59} Meta_exclam {2 60} Meta_one {2 61} Meta_exclam {2 62} Meta_one {2 63} Meta_exclam {2 64} one {2 65} exclam {2 66} one {2 67} exclam {2 68} one {2 69} exclam {2 70} one {2 71} exclam {2 72} Meta_one {2 73} Meta_exclam {2 74} Meta_one {2 75} Meta_exclam {2 76} Meta_one {2 77} Meta_exclam {2 78} Meta_one {2 79} Meta_exclam {2 80} one {2 81} exclam {2 82} one {2 83} exclam {2 84} one {2 85} exclam {2 86} one {2 87} exclam {2 88} Meta_one {2 89} Meta_exclam {2 90} Meta_one {2 91} Meta_exclam {2 92} Meta_one {2 93} Meta_exclam {2 94} Meta_one {2 95} Meta_exclam {2 96} one {2 97} exclam {2 98} one {2 99} exclam {2 100} one {2 101} exclam {2 102} one {2 103} exclam {2 104} Meta_one {2 105} Meta_exclam {2 106} Meta_one {2 107} Meta_exclam {2 108} Meta_one {2 109} Meta_exclam {2 110} Meta_one {2 111} Meta_exclam {2 112} one {2 113} exclam {2 114} one {2 115} exclam {2 116} one {2 117} exclam {2 118} one {2 119} exclam {2 120} Meta_one {2 121} Meta_exclam {2 122} Meta_one {2 123} Meta_exclam {2 124} Meta_one {2 125} Meta_exclam {2 126} Meta_one {2 127} Meta_exclam {3 0} two {3 1} at {3 2} two {3 3} at {3 4} nul {3 5} nul {3 6} nul {3 7} nul {3 8} Meta_two {3 9} Meta_at {3 10} Meta_two {3 11} Meta_at {3 12} Meta_nul {3 13} Meta_nul {3 14} Meta_nul {3 15} Meta_nul {3 16} two {3 17} at {3 18} two {3 19} at {3 20} nul {3 21} nul {3 22} nul {3 23} nul {3 24} Meta_two {3 25} Meta_at {3 26} Meta_two {3 27} Meta_at {3 28} Meta_nul {3 29} Meta_nul {3 30} Meta_nul {3 31} Meta_nul {3 32} two {3 33} at {3 34} two {3 35} at {3 36} nul {3 37} nul {3 38} nul {3 39} nul {3 40} Meta_two {3 41} Meta_at {3 42} Meta_two {3 43} Meta_at {3 44} Meta_nul {3 45} Meta_nul {3 46} Meta_nul {3 47} Meta_nul {3 48} two {3 49} at {3 50} two {3 51} at {3 52} nul {3 53} nul {3 54} nul {3 55} nul {3 56} Meta_two {3 57} Meta_at {3 58} Meta_two {3 59} Meta_at {3 60} Meta_nul {3 61} Meta_nul {3 62} Meta_nul {3 63} Meta_nul {3 64} two {3 65} at {3 66} two {3 67} at {3 68} nul {3 69} nul {3 70} nul {3 71} nul {3 72} Meta_two {3 73} Meta_at {3 74} Meta_two {3 75} Meta_at {3 76} Meta_nul {3 77} Meta_nul {3 78} Meta_nul {3 79} Meta_nul {3 80} two {3 81} at {3 82} two {3 83} at {3 84} nul {3 85} nul {3 86} nul {3 87} nul {3 88} Meta_two {3 89} Meta_at {3 90} Meta_two {3 91} Meta_at {3 92} Meta_nul {3 93} Meta_nul {3 94} Meta_nul {3 95} Meta_nul {3 96} two {3 97} at {3 98} two {3 99} at {3 100} nul {3 101} nul {3 102} nul {3 103} nul {3 104} Meta_two {3 105} Meta_at {3 106} Meta_two {3 107} Meta_at {3 108} Meta_nul {3 109} Meta_nul {3 110} Meta_nul {3 111} Meta_nul {3 112} two {3 113} at {3 114} two {3 115} at {3 116} nul {3 117} nul {3 118} nul {3 119} nul {3 120} Meta_two {3 121} Meta_at {3 122} Meta_two {3 123} Meta_at {3 124} Meta_nul {3 125} Meta_nul {3 126} Meta_nul {3 127} Meta_nul {4 0} three {4 1} numbersign {4 2} three {4 3} numbersign {4 4} three {4 5} numbersign {4 6} three {4 7} numbersign {4 8} Meta_three {4 9} Meta_numbersign {4 10} Meta_three {4 11} Meta_numbersign {4 12} Meta_three {4 13} Meta_numbersign {4 14} Meta_three {4 15} Meta_numbersign {4 16} three {4 17} numbersign {4 18} three {4 19} numbersign {4 20} three {4 21} numbersign {4 22} three {4 23} numbersign {4 24} Meta_three {4 25} Meta_numbersign {4 26} Meta_three {4 27} Meta_numbersign {4 28} Meta_three {4 29} Meta_numbersign {4 30} Meta_three {4 31} Meta_numbersign {4 32} three {4 33} numbersign {4 34} three {4 35} numbersign {4 36} three {4 37} numbersign {4 38} three {4 39} numbersign {4 40} Meta_three {4 41} Meta_numbersign {4 42} Meta_three {4 43} Meta_numbersign {4 44} Meta_three {4 45} Meta_numbersign {4 46} Meta_three {4 47} Meta_numbersign {4 48} three {4 49} numbersign {4 50} three {4 51} numbersign {4 52} three {4 53} numbersign {4 54} three {4 55} numbersign {4 56} Meta_three {4 57} Meta_numbersign {4 58} Meta_three {4 59} Meta_numbersign {4 60} Meta_three {4 61} Meta_numbersign {4 62} Meta_three {4 63} Meta_numbersign {4 64} three {4 65} numbersign {4 66} three {4 67} numbersign {4 68} three {4 69} numbersign {4 70} three {4 71} numbersign {4 72} Meta_three {4 73} Meta_numbersign {4 74} Meta_three {4 75} Meta_numbersign {4 76} Meta_three {4 77} Meta_numbersign {4 78} Meta_three {4 79} Meta_numbersign {4 80} three {4 81} numbersign {4 82} three {4 83} numbersign {4 84} three {4 85} numbersign {4 86} three {4 87} numbersign {4 88} Meta_three {4 89} Meta_numbersign {4 90} Meta_three {4 91} Meta_numbersign {4 92} Meta_three {4 93} Meta_numbersign {4 94} Meta_three {4 95} Meta_numbersign {4 96} three {4 97} numbersign {4 98} three {4 99} numbersign {4 100} three {4 101} numbersign {4 102} three {4 103} numbersign {4 104} Meta_three {4 105} Meta_numbersign {4 106} Meta_three {4 107} Meta_numbersign {4 108} Meta_three {4 109} Meta_numbersign {4 110} Meta_three {4 111} Meta_numbersign {4 112} three {4 113} numbersign {4 114} three {4 115} numbersign {4 116} three {4 117} numbersign {4 118} three {4 119} numbersign {4 120} Meta_three {4 121} Meta_numbersign {4 122} Meta_three {4 123} Meta_numbersign {4 124} Meta_three {4 125} Meta_numbersign {4 126} Meta_three {4 127} Meta_numbersign {5 0} four {5 1} dollar {5 2} four {5 3} dollar {5 4} four {5 5} dollar {5 6} four {5 7} dollar {5 8} Meta_four {5 9} Meta_dollar {5 10} Meta_four {5 11} Meta_dollar {5 12} Meta_four {5 13} Meta_dollar {5 14} Meta_four {5 15} Meta_dollar {5 16} four {5 17} dollar {5 18} four {5 19} dollar {5 20} four {5 21} dollar {5 22} four {5 23} dollar {5 24} Meta_four {5 25} Meta_dollar {5 26} Meta_four {5 27} Meta_dollar {5 28} Meta_four {5 29} Meta_dollar {5 30} Meta_four {5 31} Meta_dollar {5 32} four {5 33} dollar {5 34} four {5 35} dollar {5 36} four {5 37} dollar {5 38} four {5 39} dollar {5 40} Meta_four {5 41} Meta_dollar {5 42} Meta_four {5 43} Meta_dollar {5 44} Meta_four {5 45} Meta_dollar {5 46} Meta_four {5 47} Meta_dollar {5 48} four {5 49} dollar {5 50} four {5 51} dollar {5 52} four {5 53} dollar {5 54} four {5 55} dollar {5 56} Meta_four {5 57} Meta_dollar {5 58} Meta_four {5 59} Meta_dollar {5 60} Meta_four {5 61} Meta_dollar {5 62} Meta_four {5 63} Meta_dollar {5 64} four {5 65} dollar {5 66} four {5 67} dollar {5 68} four {5 69} dollar {5 70} four {5 71} dollar {5 72} Meta_four {5 73} Meta_dollar {5 74} Meta_four {5 75} Meta_dollar {5 76} Meta_four {5 77} Meta_dollar {5 78} Meta_four {5 79} Meta_dollar {5 80} four {5 81} dollar {5 82} four {5 83} dollar {5 84} four {5 85} dollar {5 86} four {5 87} dollar {5 88} Meta_four {5 89} Meta_dollar {5 90} Meta_four {5 91} Meta_dollar {5 92} Meta_four {5 93} Meta_dollar {5 94} Meta_four {5 95} Meta_dollar {5 96} four {5 97} dollar {5 98} four {5 99} dollar {5 100} four {5 101} dollar {5 102} four {5 103} dollar {5 104} Meta_four {5 105} Meta_dollar {5 106} Meta_four {5 107} Meta_dollar {5 108} Meta_four {5 109} Meta_dollar {5 110} Meta_four {5 111} Meta_dollar {5 112} four {5 113} dollar {5 114} four {5 115} dollar {5 116} four {5 117} dollar {5 118} four {5 119} dollar {5 120} Meta_four {5 121} Meta_dollar {5 122} Meta_four {5 123} Meta_dollar {5 124} Meta_four {5 125} Meta_dollar {5 126} Meta_four {5 127} Meta_dollar {6 0} five {6 1} percent {6 2} five {6 3} percent {6 4} five {6 5} percent {6 6} five {6 7} percent {6 8} Meta_five {6 9} Meta_percent {6 10} Meta_five {6 11} Meta_percent {6 12} Meta_five {6 13} Meta_percent {6 14} Meta_five {6 15} Meta_percent {6 16} five {6 17} percent {6 18} five {6 19} percent {6 20} five {6 21} percent {6 22} five {6 23} percent {6 24} Meta_five {6 25} Meta_percent {6 26} Meta_five {6 27} Meta_percent {6 28} Meta_five {6 29} Meta_percent {6 30} Meta_five {6 31} Meta_percent {6 32} five {6 33} percent {6 34} five {6 35} percent {6 36} five {6 37} percent {6 38} five {6 39} percent {6 40} Meta_five {6 41} Meta_percent {6 42} Meta_five {6 43} Meta_percent {6 44} Meta_five {6 45} Meta_percent {6 46} Meta_five {6 47} Meta_percent {6 48} five {6 49} percent {6 50} five {6 51} percent {6 52} five {6 53} percent {6 54} five {6 55} percent {6 56} Meta_five {6 57} Meta_percent {6 58} Meta_five {6 59} Meta_percent {6 60} Meta_five {6 61} Meta_percent {6 62} Meta_five {6 63} Meta_percent {6 64} five {6 65} percent {6 66} five {6 67} percent {6 68} five {6 69} percent {6 70} five {6 71} percent {6 72} Meta_five {6 73} Meta_percent {6 74} Meta_five {6 75} Meta_percent {6 76} Meta_five {6 77} Meta_percent {6 78} Meta_five {6 79} Meta_percent {6 80} five {6 81} percent {6 82} five {6 83} percent {6 84} five {6 85} percent {6 86} five {6 87} percent {6 88} Meta_five {6 89} Meta_percent {6 90} Meta_five {6 91} Meta_percent {6 92} Meta_five {6 93} Meta_percent {6 94} Meta_five {6 95} Meta_percent {6 96} five {6 97} percent {6 98} five {6 99} percent {6 100} five {6 101} percent {6 102} five {6 103} percent {6 104} Meta_five {6 105} Meta_percent {6 106} Meta_five {6 107} Meta_percent {6 108} Meta_five {6 109} Meta_percent {6 110} Meta_five {6 111} Meta_percent {6 112} five {6 113} percent {6 114} five {6 115} percent {6 116} five {6 117} percent {6 118} five {6 119} percent {6 120} Meta_five {6 121} Meta_percent {6 122} Meta_five {6 123} Meta_percent {6 124} Meta_five {6 125} Meta_percent {6 126} Meta_five {6 127} Meta_percent {7 0} six {7 1} asciicircum {7 2} six {7 3} asciicircum {7 4} Control_asciicircum {7 5} Control_asciicircum {7 6} Control_asciicircum {7 7} Control_asciicircum {7 8} Meta_six {7 9} Meta_asciicircum {7 10} Meta_six {7 11} Meta_asciicircum {7 12} Meta_Control_asciicircum {7 13} Meta_Control_asciicircum {7 14} Meta_Control_asciicircum {7 15} Meta_Control_asciicircum {7 16} six {7 17} asciicircum {7 18} six {7 19} asciicircum {7 20} Control_asciicircum {7 21} Control_asciicircum {7 22} Control_asciicircum {7 23} Control_asciicircum {7 24} Meta_six {7 25} Meta_asciicircum {7 26} Meta_six {7 27} Meta_asciicircum {7 28} Meta_Control_asciicircum {7 29} Meta_Control_asciicircum {7 30} Meta_Control_asciicircum {7 31} Meta_Control_asciicircum {7 32} six {7 33} asciicircum {7 34} six {7 35} asciicircum {7 36} Control_asciicircum {7 37} Control_asciicircum {7 38} Control_asciicircum {7 39} Control_asciicircum {7 40} Meta_six {7 41} Meta_asciicircum {7 42} Meta_six {7 43} Meta_asciicircum {7 44} Meta_Control_asciicircum {7 45} Meta_Control_asciicircum {7 46} Meta_Control_asciicircum {7 47} Meta_Control_asciicircum {7 48} six {7 49} asciicircum {7 50} six {7 51} asciicircum {7 52} Control_asciicircum {7 53} Control_asciicircum {7 54} Control_asciicircum {7 55} Control_asciicircum {7 56} Meta_six {7 57} Meta_asciicircum {7 58} Meta_six {7 59} Meta_asciicircum {7 60} Meta_Control_asciicircum {7 61} Meta_Control_asciicircum {7 62} Meta_Control_asciicircum {7 63} Meta_Control_asciicircum {7 64} six {7 65} asciicircum {7 66} six {7 67} asciicircum {7 68} Control_asciicircum {7 69} Control_asciicircum {7 70} Control_asciicircum {7 71} Control_asciicircum {7 72} Meta_six {7 73} Meta_asciicircum {7 74} Meta_six {7 75} Meta_asciicircum {7 76} Meta_Control_asciicircum {7 77} Meta_Control_asciicircum {7 78} Meta_Control_asciicircum {7 79} Meta_Control_asciicircum {7 80} six {7 81} asciicircum {7 82} six {7 83} asciicircum {7 84} Control_asciicircum {7 85} Control_asciicircum {7 86} Control_asciicircum {7 87} Control_asciicircum {7 88} Meta_six {7 89} Meta_asciicircum {7 90} Meta_six {7 91} Meta_asciicircum {7 92} Meta_Control_asciicircum {7 93} Meta_Control_asciicircum {7 94} Meta_Control_asciicircum {7 95} Meta_Control_asciicircum {7 96} six {7 97} asciicircum {7 98} six {7 99} asciicircum {7 100} Control_asciicircum {7 101} Control_asciicircum {7 102} Control_asciicircum {7 103} Control_asciicircum {7 104} Meta_six {7 105} Meta_asciicircum {7 106} Meta_six {7 107} Meta_asciicircum {7 108} Meta_Control_asciicircum {7 109} Meta_Control_asciicircum {7 110} Meta_Control_asciicircum {7 111} Meta_Control_asciicircum {7 112} six {7 113} asciicircum {7 114} six {7 115} asciicircum {7 116} Control_asciicircum {7 117} Control_asciicircum {7 118} Control_asciicircum {7 119} Control_asciicircum {7 120} Meta_six {7 121} Meta_asciicircum {7 122} Meta_six {7 123} Meta_asciicircum {7 124} Meta_Control_asciicircum {7 125} Meta_Control_asciicircum {7 126} Meta_Control_asciicircum {7 127} Meta_Control_asciicircum {8 0} seven {8 1} ampersand {8 2} seven {8 3} ampersand {8 4} seven {8 5} ampersand {8 6} seven {8 7} ampersand {8 8} Meta_seven {8 9} Meta_ampersand {8 10} Meta_seven {8 11} Meta_ampersand {8 12} Meta_seven {8 13} Meta_ampersand {8 14} Meta_seven {8 15} Meta_ampersand {8 16} seven {8 17} ampersand {8 18} seven {8 19} ampersand {8 20} seven {8 21} ampersand {8 22} seven {8 23} ampersand {8 24} Meta_seven {8 25} Meta_ampersand {8 26} Meta_seven {8 27} Meta_ampersand {8 28} Meta_seven {8 29} Meta_ampersand {8 30} Meta_seven {8 31} Meta_ampersand {8 32} seven {8 33} ampersand {8 34} seven {8 35} ampersand {8 36} seven {8 37} ampersand {8 38} seven {8 39} ampersand {8 40} Meta_seven {8 41} Meta_ampersand {8 42} Meta_seven {8 43} Meta_ampersand {8 44} Meta_seven {8 45} Meta_ampersand {8 46} Meta_seven {8 47} Meta_ampersand {8 48} seven {8 49} ampersand {8 50} seven {8 51} ampersand {8 52} seven {8 53} ampersand {8 54} seven {8 55} ampersand {8 56} Meta_seven {8 57} Meta_ampersand {8 58} Meta_seven {8 59} Meta_ampersand {8 60} Meta_seven {8 61} Meta_ampersand {8 62} Meta_seven {8 63} Meta_ampersand {8 64} seven {8 65} ampersand {8 66} seven {8 67} ampersand {8 68} seven {8 69} ampersand {8 70} seven {8 71} ampersand {8 72} Meta_seven {8 73} Meta_ampersand {8 74} Meta_seven {8 75} Meta_ampersand {8 76} Meta_seven {8 77} Meta_ampersand {8 78} Meta_seven {8 79} Meta_ampersand {8 80} seven {8 81} ampersand {8 82} seven {8 83} ampersand {8 84} seven {8 85} ampersand {8 86} seven {8 87} ampersand {8 88} Meta_seven {8 89} Meta_ampersand {8 90} Meta_seven {8 91} Meta_ampersand {8 92} Meta_seven {8 93} Meta_ampersand {8 94} Meta_seven {8 95} Meta_ampersand {8 96} seven {8 97} ampersand {8 98} seven {8 99} ampersand {8 100} seven {8 101} ampersand {8 102} seven {8 103} ampersand {8 104} Meta_seven {8 105} Meta_ampersand {8 106} Meta_seven {8 107} Meta_ampersand {8 108} Meta_seven {8 109} Meta_ampersand {8 110} Meta_seven {8 111} Meta_ampersand {8 112} seven {8 113} ampersand {8 114} seven {8 115} ampersand {8 116} seven {8 117} ampersand {8 118} seven {8 119} ampersand {8 120} Meta_seven {8 121} Meta_ampersand {8 122} Meta_seven {8 123} Meta_ampersand {8 124} Meta_seven {8 125} Meta_ampersand {8 126} Meta_seven {8 127} Meta_ampersand {9 0} eight {9 1} asterisk {9 2} eight {9 3} asterisk {9 4} eight {9 5} asterisk {9 6} eight {9 7} asterisk {9 8} Meta_eight {9 9} Meta_asterisk {9 10} Meta_eight {9 11} Meta_asterisk {9 12} Meta_eight {9 13} Meta_asterisk {9 14} Meta_eight {9 15} Meta_asterisk {9 16} eight {9 17} asterisk {9 18} eight {9 19} asterisk {9 20} eight {9 21} asterisk {9 22} eight {9 23} asterisk {9 24} Meta_eight {9 25} Meta_asterisk {9 26} Meta_eight {9 27} Meta_asterisk {9 28} Meta_eight {9 29} Meta_asterisk {9 30} Meta_eight {9 31} Meta_asterisk {9 32} eight {9 33} asterisk {9 34} eight {9 35} asterisk {9 36} eight {9 37} asterisk {9 38} eight {9 39} asterisk {9 40} Meta_eight {9 41} Meta_asterisk {9 42} Meta_eight {9 43} Meta_asterisk {9 44} Meta_eight {9 45} Meta_asterisk {9 46} Meta_eight {9 47} Meta_asterisk {9 48} eight {9 49} asterisk {9 50} eight {9 51} asterisk {9 52} eight {9 53} asterisk {9 54} eight {9 55} asterisk {9 56} Meta_eight {9 57} Meta_asterisk {9 58} Meta_eight {9 59} Meta_asterisk {9 60} Meta_eight {9 61} Meta_asterisk {9 62} Meta_eight {9 63} Meta_asterisk {9 64} eight {9 65} asterisk {9 66} eight {9 67} asterisk {9 68} eight {9 69} asterisk {9 70} eight {9 71} asterisk {9 72} Meta_eight {9 73} Meta_asterisk {9 74} Meta_eight {9 75} Meta_asterisk {9 76} Meta_eight {9 77} Meta_asterisk {9 78} Meta_eight {9 79} Meta_asterisk {9 80} eight {9 81} asterisk {9 82} eight {9 83} asterisk {9 84} eight {9 85} asterisk {9 86} eight {9 87} asterisk {9 88} Meta_eight {9 89} Meta_asterisk {9 90} Meta_eight {9 91} Meta_asterisk {9 92} Meta_eight {9 93} Meta_asterisk {9 94} Meta_eight {9 95} Meta_asterisk {9 96} eight {9 97} asterisk {9 98} eight {9 99} asterisk {9 100} eight {9 101} asterisk {9 102} eight {9 103} asterisk {9 104} Meta_eight {9 105} Meta_asterisk {9 106} Meta_eight {9 107} Meta_asterisk {9 108} Meta_eight {9 109} Meta_asterisk {9 110} Meta_eight {9 111} Meta_asterisk {9 112} eight {9 113} asterisk {9 114} eight {9 115} asterisk {9 116} eight {9 117} asterisk {9 118} eight {9 119} asterisk {9 120} Meta_eight {9 121} Meta_asterisk {9 122} Meta_eight {9 123} Meta_asterisk {9 124} Meta_eight {9 125} Meta_asterisk {9 126} Meta_eight {9 127} Meta_asterisk {10 0} nine {10 1} parenleft {10 2} nine {10 3} parenleft {10 4} nine {10 5} parenleft {10 6} nine {10 7} parenleft {10 8} Meta_nine {10 9} Meta_parenleft {10 10} Meta_nine {10 11} Meta_parenleft {10 12} Meta_nine {10 13} Meta_parenleft {10 14} Meta_nine {10 15} Meta_parenleft {10 16} nine {10 17} parenleft {10 18} nine {10 19} parenleft {10 20} nine {10 21} parenleft {10 22} nine {10 23} parenleft {10 24} Meta_nine {10 25} Meta_parenleft {10 26} Meta_nine {10 27} Meta_parenleft {10 28} Meta_nine {10 29} Meta_parenleft {10 30} Meta_nine {10 31} Meta_parenleft {10 32} nine {10 33} parenleft {10 34} nine {10 35} parenleft {10 36} nine {10 37} parenleft {10 38} nine {10 39} parenleft {10 40} Meta_nine {10 41} Meta_parenleft {10 42} Meta_nine {10 43} Meta_parenleft {10 44} Meta_nine {10 45} Meta_parenleft {10 46} Meta_nine {10 47} Meta_parenleft {10 48} nine {10 49} parenleft {10 50} nine {10 51} parenleft {10 52} nine {10 53} parenleft {10 54} nine {10 55} parenleft {10 56} Meta_nine {10 57} Meta_parenleft {10 58} Meta_nine {10 59} Meta_parenleft {10 60} Meta_nine {10 61} Meta_parenleft {10 62} Meta_nine {10 63} Meta_parenleft {10 64} nine {10 65} parenleft {10 66} nine {10 67} parenleft {10 68} nine {10 69} parenleft {10 70} nine {10 71} parenleft {10 72} Meta_nine {10 73} Meta_parenleft {10 74} Meta_nine {10 75} Meta_parenleft {10 76} Meta_nine {10 77} Meta_parenleft {10 78} Meta_nine {10 79} Meta_parenleft {10 80} nine {10 81} parenleft {10 82} nine {10 83} parenleft {10 84} nine {10 85} parenleft {10 86} nine {10 87} parenleft {10 88} Meta_nine {10 89} Meta_parenleft {10 90} Meta_nine {10 91} Meta_parenleft {10 92} Meta_nine {10 93} Meta_parenleft {10 94} Meta_nine {10 95} Meta_parenleft {10 96} nine {10 97} parenleft {10 98} nine {10 99} parenleft {10 100} nine {10 101} parenleft {10 102} nine {10 103} parenleft {10 104} Meta_nine {10 105} Meta_parenleft {10 106} Meta_nine {10 107} Meta_parenleft {10 108} Meta_nine {10 109} Meta_parenleft {10 110} Meta_nine {10 111} Meta_parenleft {10 112} nine {10 113} parenleft {10 114} nine {10 115} parenleft {10 116} nine {10 117} parenleft {10 118} nine {10 119} parenleft {10 120} Meta_nine {10 121} Meta_parenleft {10 122} Meta_nine {10 123} Meta_parenleft {10 124} Meta_nine {10 125} Meta_parenleft {10 126} Meta_nine {10 127} Meta_parenleft {11 0} zero {11 1} parenright {11 2} zero {11 3} parenright {11 4} zero {11 5} parenright {11 6} zero {11 7} parenright {11 8} Meta_zero {11 9} Meta_parenright {11 10} Meta_zero {11 11} Meta_parenright {11 12} Meta_zero {11 13} Meta_parenright {11 14} Meta_zero {11 15} Meta_parenright {11 16} zero {11 17} parenright {11 18} zero {11 19} parenright {11 20} zero {11 21} parenright {11 22} zero {11 23} parenright {11 24} Meta_zero {11 25} Meta_parenright {11 26} Meta_zero {11 27} Meta_parenright {11 28} Meta_zero {11 29} Meta_parenright {11 30} Meta_zero {11 31} Meta_parenright {11 32} zero {11 33} parenright {11 34} zero {11 35} parenright {11 36} zero {11 37} parenright {11 38} zero {11 39} parenright {11 40} Meta_zero {11 41} Meta_parenright {11 42} Meta_zero {11 43} Meta_parenright {11 44} Meta_zero {11 45} Meta_parenright {11 46} Meta_zero {11 47} Meta_parenright {11 48} zero {11 49} parenright {11 50} zero {11 51} parenright {11 52} zero {11 53} parenright {11 54} zero {11 55} parenright {11 56} Meta_zero {11 57} Meta_parenright {11 58} Meta_zero {11 59} Meta_parenright {11 60} Meta_zero {11 61} Meta_parenright {11 62} Meta_zero {11 63} Meta_parenright {11 64} zero {11 65} parenright {11 66} zero {11 67} parenright {11 68} zero {11 69} parenright {11 70} zero {11 71} parenright {11 72} Meta_zero {11 73} Meta_parenright {11 74} Meta_zero {11 75} Meta_parenright {11 76} Meta_zero {11 77} Meta_parenright {11 78} Meta_zero {11 79} Meta_parenright {11 80} zero {11 81} parenright {11 82} zero {11 83} parenright {11 84} zero {11 85} parenright {11 86} zero {11 87} parenright {11 88} Meta_zero {11 89} Meta_parenright {11 90} Meta_zero {11 91} Meta_parenright {11 92} Meta_zero {11 93} Meta_parenright {11 94} Meta_zero {11 95} Meta_parenright {11 96} zero {11 97} parenright {11 98} zero {11 99} parenright {11 100} zero {11 101} parenright {11 102} zero {11 103} parenright {11 104} Meta_zero {11 105} Meta_parenright {11 106} Meta_zero {11 107} Meta_parenright {11 108} Meta_zero {11 109} Meta_parenright {11 110} Meta_zero {11 111} Meta_parenright {11 112} zero {11 113} parenright {11 114} zero {11 115} parenright {11 116} zero {11 117} parenright {11 118} zero {11 119} parenright {11 120} Meta_zero {11 121} Meta_parenright {11 122} Meta_zero {11 123} Meta_parenright {11 124} Meta_zero {11 125} Meta_parenright {11 126} Meta_zero {11 127} Meta_parenright {12 0} minus {12 1} underscore {12 2} minus {12 3} underscore {12 4} Control_underscore {12 5} Control_underscore {12 6} Control_underscore {12 7} Control_underscore {12 8} Meta_minus {12 9} Meta_underscore {12 10} Meta_minus {12 11} Meta_underscore {12 12} Meta_Control_underscore {12 13} Meta_Control_underscore {12 14} Meta_Control_underscore {12 15} Meta_Control_underscore {12 16} minus {12 17} underscore {12 18} minus {12 19} underscore {12 20} Control_underscore {12 21} Control_underscore {12 22} Control_underscore {12 23} Control_underscore {12 24} Meta_minus {12 25} Meta_underscore {12 26} Meta_minus {12 27} Meta_underscore {12 28} Meta_Control_underscore {12 29} Meta_Control_underscore {12 30} Meta_Control_underscore {12 31} Meta_Control_underscore {12 32} minus {12 33} underscore {12 34} minus {12 35} underscore {12 36} Control_underscore {12 37} Control_underscore {12 38} Control_underscore {12 39} Control_underscore {12 40} Meta_minus {12 41} Meta_underscore {12 42} Meta_minus {12 43} Meta_underscore {12 44} Meta_Control_underscore {12 45} Meta_Control_underscore {12 46} Meta_Control_underscore {12 47} Meta_Control_underscore {12 48} minus {12 49} underscore {12 50} minus {12 51} underscore {12 52} Control_underscore {12 53} Control_underscore {12 54} Control_underscore {12 55} Control_underscore {12 56} Meta_minus {12 57} Meta_underscore {12 58} Meta_minus {12 59} Meta_underscore {12 60} Meta_Control_underscore {12 61} Meta_Control_underscore {12 62} Meta_Control_underscore {12 63} Meta_Control_underscore {12 64} minus {12 65} underscore {12 66} minus {12 67} underscore {12 68} Control_underscore {12 69} Control_underscore {12 70} Control_underscore {12 71} Control_underscore {12 72} Meta_minus {12 73} Meta_underscore {12 74} Meta_minus {12 75} Meta_underscore {12 76} Meta_Control_underscore {12 77} Meta_Control_underscore {12 78} Meta_Control_underscore {12 79} Meta_Control_underscore {12 80} minus {12 81} underscore {12 82} minus {12 83} underscore {12 84} Control_underscore {12 85} Control_underscore {12 86} Control_underscore {12 87} Control_underscore {12 88} Meta_minus {12 89} Meta_underscore {12 90} Meta_minus {12 91} Meta_underscore {12 92} Meta_Control_underscore {12 93} Meta_Control_underscore {12 94} Meta_Control_underscore {12 95} Meta_Control_underscore {12 96} minus {12 97} underscore {12 98} minus {12 99} underscore {12 100} Control_underscore {12 101} Control_underscore {12 102} Control_underscore {12 103} Control_underscore {12 104} Meta_minus {12 105} Meta_underscore {12 106} Meta_minus {12 107} Meta_underscore {12 108} Meta_Control_underscore {12 109} Meta_Control_underscore {12 110} Meta_Control_underscore {12 111} Meta_Control_underscore {12 112} minus {12 113} underscore {12 114} minus {12 115} underscore {12 116} Control_underscore {12 117} Control_underscore {12 118} Control_underscore {12 119} Control_underscore {12 120} Meta_minus {12 121} Meta_underscore {12 122} Meta_minus {12 123} Meta_underscore {12 124} Meta_Control_underscore {12 125} Meta_Control_underscore {12 126} Meta_Control_underscore {12 127} Meta_Control_underscore {13 0} equal {13 1} plus {13 2} equal {13 3} plus {13 4} equal {13 5} plus {13 6} equal {13 7} plus {13 8} Meta_equal {13 9} Meta_plus {13 10} Meta_equal {13 11} Meta_plus {13 12} Meta_equal {13 13} Meta_plus {13 14} Meta_equal {13 15} Meta_plus {13 16} equal {13 17} plus {13 18} equal {13 19} plus {13 20} equal {13 21} plus {13 22} equal {13 23} plus {13 24} Meta_equal {13 25} Meta_plus {13 26} Meta_equal {13 27} Meta_plus {13 28} Meta_equal {13 29} Meta_plus {13 30} Meta_equal {13 31} Meta_plus {13 32} equal {13 33} plus {13 34} equal {13 35} plus {13 36} equal {13 37} plus {13 38} equal {13 39} plus {13 40} Meta_equal {13 41} Meta_plus {13 42} Meta_equal {13 43} Meta_plus {13 44} Meta_equal {13 45} Meta_plus {13 46} Meta_equal {13 47} Meta_plus {13 48} equal {13 49} plus {13 50} equal {13 51} plus {13 52} equal {13 53} plus {13 54} equal {13 55} plus {13 56} Meta_equal {13 57} Meta_plus {13 58} Meta_equal {13 59} Meta_plus {13 60} Meta_equal {13 61} Meta_plus {13 62} Meta_equal {13 63} Meta_plus {13 64} equal {13 65} plus {13 66} equal {13 67} plus {13 68} equal {13 69} plus {13 70} equal {13 71} plus {13 72} Meta_equal {13 73} Meta_plus {13 74} Meta_equal {13 75} Meta_plus {13 76} Meta_equal {13 77} Meta_plus {13 78} Meta_equal {13 79} Meta_plus {13 80} equal {13 81} plus {13 82} equal {13 83} plus {13 84} equal {13 85} plus {13 86} equal {13 87} plus {13 88} Meta_equal {13 89} Meta_plus {13 90} Meta_equal {13 91} Meta_plus {13 92} Meta_equal {13 93} Meta_plus {13 94} Meta_equal {13 95} Meta_plus {13 96} equal {13 97} plus {13 98} equal {13 99} plus {13 100} equal {13 101} plus {13 102} equal {13 103} plus {13 104} Meta_equal {13 105} Meta_plus {13 106} Meta_equal {13 107} Meta_plus {13 108} Meta_equal {13 109} Meta_plus {13 110} Meta_equal {13 111} Meta_plus {13 112} equal {13 113} plus {13 114} equal {13 115} plus {13 116} equal {13 117} plus {13 118} equal {13 119} plus {13 120} Meta_equal {13 121} Meta_plus {13 122} Meta_equal {13 123} Meta_plus {13 124} Meta_equal {13 125} Meta_plus {13 126} Meta_equal {13 127} Meta_plus {14 0} Delete {14 1} Delete {14 2} Delete {14 3} Delete {14 4} BackSpace {14 5} BackSpace {14 6} BackSpace {14 7} BackSpace {14 8} Meta_Delete {14 9} Meta_Delete {14 10} Meta_Delete {14 11} Meta_Delete {14 12} Meta_BackSpace {14 13} Meta_BackSpace {14 14} Meta_BackSpace {14 15} Meta_BackSpace {14 16} Delete {14 17} Delete {14 18} Delete {14 19} Delete {14 20} BackSpace {14 21} BackSpace {14 22} BackSpace {14 23} BackSpace {14 24} Meta_Delete {14 25} Meta_Delete {14 26} Meta_Delete {14 27} Meta_Delete {14 28} Meta_BackSpace {14 29} Meta_BackSpace {14 30} Meta_BackSpace {14 31} Meta_BackSpace {14 32} Delete {14 33} Delete {14 34} Delete {14 35} Delete {14 36} BackSpace {14 37} BackSpace {14 38} BackSpace {14 39} BackSpace {14 40} Meta_Delete {14 41} Meta_Delete {14 42} Meta_Delete {14 43} Meta_Delete {14 44} Meta_BackSpace {14 45} Meta_BackSpace {14 46} Meta_BackSpace {14 47} Meta_BackSpace {14 48} Delete {14 49} Delete {14 50} Delete {14 51} Delete {14 52} BackSpace {14 53} BackSpace {14 54} BackSpace {14 55} BackSpace {14 56} Meta_Delete {14 57} Meta_Delete {14 58} Meta_Delete {14 59} Meta_Delete {14 60} Meta_BackSpace {14 61} Meta_BackSpace {14 62} Meta_BackSpace {14 63} Meta_BackSpace {14 64} Delete {14 65} Delete {14 66} Delete {14 67} Delete {14 68} BackSpace {14 69} BackSpace {14 70} BackSpace {14 71} BackSpace {14 72} Meta_Delete {14 73} Meta_Delete {14 74} Meta_Delete {14 75} Meta_Delete {14 76} Meta_BackSpace {14 77} Meta_BackSpace {14 78} Meta_BackSpace {14 79} Meta_BackSpace {14 80} Delete {14 81} Delete {14 82} Delete {14 83} Delete {14 84} BackSpace {14 85} BackSpace {14 86} BackSpace {14 87} BackSpace {14 88} Meta_Delete {14 89} Meta_Delete {14 90} Meta_Delete {14 91} Meta_Delete {14 92} Meta_BackSpace {14 93} Meta_BackSpace {14 94} Meta_BackSpace {14 95} Meta_BackSpace {14 96} Delete {14 97} Delete {14 98} Delete {14 99} Delete {14 100} BackSpace {14 101} BackSpace {14 102} BackSpace {14 103} BackSpace {14 104} Meta_Delete {14 105} Meta_Delete {14 106} Meta_Delete {14 107} Meta_Delete {14 108} Meta_BackSpace {14 109} Meta_BackSpace {14 110} Meta_BackSpace {14 111} Meta_BackSpace {14 112} Delete {14 113} Delete {14 114} Delete {14 115} Delete {14 116} BackSpace {14 117} BackSpace {14 118} BackSpace {14 119} BackSpace {14 120} Meta_Delete {14 121} Meta_Delete {14 122} Meta_Delete {14 123} Meta_Delete {14 124} Meta_BackSpace {14 125} Meta_BackSpace {14 126} Meta_BackSpace {14 127} Meta_BackSpace {15 0} Tab {15 1} Meta_Tab {15 2} Tab {15 3} Meta_Tab {15 4} Tab {15 5} Tab {15 6} Tab {15 7} Tab {15 8} Meta_Tab {15 9} Meta_Tab {15 10} Meta_Tab {15 11} Meta_Tab {15 12} Meta_Tab {15 13} Meta_Tab {15 14} Meta_Tab {15 15} Meta_Tab {15 16} Tab {15 17} Meta_Tab {15 18} Tab {15 19} Meta_Tab {15 20} Tab {15 21} Tab {15 22} Tab {15 23} Tab {15 24} Meta_Tab {15 25} Meta_Tab {15 26} Meta_Tab {15 27} Meta_Tab {15 28} Meta_Tab {15 29} Meta_Tab {15 30} Meta_Tab {15 31} Meta_Tab {15 32} Tab {15 33} Meta_Tab {15 34} Tab {15 35} Meta_Tab {15 36} Tab {15 37} Tab {15 38} Tab {15 39} Tab {15 40} Meta_Tab {15 41} Meta_Tab {15 42} Meta_Tab {15 43} Meta_Tab {15 44} Meta_Tab {15 45} Meta_Tab {15 46} Meta_Tab {15 47} Meta_Tab {15 48} Tab {15 49} Meta_Tab {15 50} Tab {15 51} Meta_Tab {15 52} Tab {15 53} Tab {15 54} Tab {15 55} Tab {15 56} Meta_Tab {15 57} Meta_Tab {15 58} Meta_Tab {15 59} Meta_Tab {15 60} Meta_Tab {15 61} Meta_Tab {15 62} Meta_Tab {15 63} Meta_Tab {15 64} Tab {15 65} Meta_Tab {15 66} Tab {15 67} Meta_Tab {15 68} Tab {15 69} Tab {15 70} Tab {15 71} Tab {15 72} Meta_Tab {15 73} Meta_Tab {15 74} Meta_Tab {15 75} Meta_Tab {15 76} Meta_Tab {15 77} Meta_Tab {15 78} Meta_Tab {15 79} Meta_Tab {15 80} Tab {15 81} Meta_Tab {15 82} Tab {15 83} Meta_Tab {15 84} Tab {15 85} Tab {15 86} Tab {15 87} Tab {15 88} Meta_Tab {15 89} Meta_Tab {15 90} Meta_Tab {15 91} Meta_Tab {15 92} Meta_Tab {15 93} Meta_Tab {15 94} Meta_Tab {15 95} Meta_Tab {15 96} Tab {15 97} Meta_Tab {15 98} Tab {15 99} Meta_Tab {15 100} Tab {15 101} Tab {15 102} Tab {15 103} Tab {15 104} Meta_Tab {15 105} Meta_Tab {15 106} Meta_Tab {15 107} Meta_Tab {15 108} Meta_Tab {15 109} Meta_Tab {15 110} Meta_Tab {15 111} Meta_Tab {15 112} Tab {15 113} Meta_Tab {15 114} Tab {15 115} Meta_Tab {15 116} Tab {15 117} Tab {15 118} Tab {15 119} Tab {15 120} Meta_Tab {15 121} Meta_Tab {15 122} Meta_Tab {15 123} Meta_Tab {15 124} Meta_Tab {15 125} Meta_Tab {15 126} Meta_Tab {15 127} Meta_Tab {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} Control_q {16 5} Control_q {16 6} Control_q {16 7} Control_q {16 8} Meta_q {16 9} Meta_Q {16 10} Meta_q {16 11} Meta_Q {16 12} Meta_Control_q {16 13} Meta_Control_q {16 14} Meta_Control_q {16 15} Meta_Control_q {16 16} q {16 17} Q {16 18} q {16 19} Q {16 20} Control_q {16 21} Control_q {16 22} Control_q {16 23} Control_q {16 24} Meta_q {16 25} Meta_Q {16 26} Meta_q {16 27} Meta_Q {16 28} Meta_Control_q {16 29} Meta_Control_q {16 30} Meta_Control_q {16 31} Meta_Control_q {16 32} q {16 33} Q {16 34} q {16 35} Q {16 36} Control_q {16 37} Control_q {16 38} Control_q {16 39} Control_q {16 40} Meta_q {16 41} Meta_Q {16 42} Meta_q {16 43} Meta_Q {16 44} Meta_Control_q {16 45} Meta_Control_q {16 46} Meta_Control_q {16 47} Meta_Control_q {16 48} q {16 49} Q {16 50} q {16 51} Q {16 52} Control_q {16 53} Control_q {16 54} Control_q {16 55} Control_q {16 56} Meta_q {16 57} Meta_Q {16 58} Meta_q {16 59} Meta_Q {16 60} Meta_Control_q {16 61} Meta_Control_q {16 62} Meta_Control_q {16 63} Meta_Control_q {16 64} Q {16 65} q {16 66} Q {16 67} q {16 68} Control_q {16 69} Control_q {16 70} Control_q {16 71} Control_q {16 72} Meta_q {16 73} Meta_Q {16 74} Meta_q {16 75} Meta_Q {16 76} Meta_Control_q {16 77} Meta_Control_q {16 78} Meta_Control_q {16 79} Meta_Control_q {16 80} Q {16 81} q {16 82} Q {16 83} q {16 84} Control_q {16 85} Control_q {16 86} Control_q {16 87} Control_q {16 88} Meta_q {16 89} Meta_Q {16 90} Meta_q {16 91} Meta_Q {16 92} Meta_Control_q {16 93} Meta_Control_q {16 94} Meta_Control_q {16 95} Meta_Control_q {16 96} Q {16 97} q {16 98} Q {16 99} q {16 100} Control_q {16 101} Control_q {16 102} Control_q {16 103} Control_q {16 104} Meta_q {16 105} Meta_Q {16 106} Meta_q {16 107} Meta_Q {16 108} Meta_Control_q {16 109} Meta_Control_q {16 110} Meta_Control_q {16 111} Meta_Control_q {16 112} Q {16 113} q {16 114} Q {16 115} q {16 116} Control_q {16 117} Control_q {16 118} Control_q {16 119} Control_q {16 120} Meta_q {16 121} Meta_Q {16 122} Meta_q {16 123} Meta_Q {16 124} Meta_Control_q {16 125} Meta_Control_q {16 126} Meta_Control_q {16 127} Meta_Control_q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} Control_w {17 5} Control_w {17 6} Control_w {17 7} Control_w {17 8} Meta_w {17 9} Meta_W {17 10} Meta_w {17 11} Meta_W {17 12} Meta_Control_w {17 13} Meta_Control_w {17 14} Meta_Control_w {17 15} Meta_Control_w {17 16} w {17 17} W {17 18} w {17 19} W {17 20} Control_w {17 21} Control_w {17 22} Control_w {17 23} Control_w {17 24} Meta_w {17 25} Meta_W {17 26} Meta_w {17 27} Meta_W {17 28} Meta_Control_w {17 29} Meta_Control_w {17 30} Meta_Control_w {17 31} Meta_Control_w {17 32} w {17 33} W {17 34} w {17 35} W {17 36} Control_w {17 37} Control_w {17 38} Control_w {17 39} Control_w {17 40} Meta_w {17 41} Meta_W {17 42} Meta_w {17 43} Meta_W {17 44} Meta_Control_w {17 45} Meta_Control_w {17 46} Meta_Control_w {17 47} Meta_Control_w {17 48} w {17 49} W {17 50} w {17 51} W {17 52} Control_w {17 53} Control_w {17 54} Control_w {17 55} Control_w {17 56} Meta_w {17 57} Meta_W {17 58} Meta_w {17 59} Meta_W {17 60} Meta_Control_w {17 61} Meta_Control_w {17 62} Meta_Control_w {17 63} Meta_Control_w {17 64} W {17 65} w {17 66} W {17 67} w {17 68} Control_w {17 69} Control_w {17 70} Control_w {17 71} Control_w {17 72} Meta_w {17 73} Meta_W {17 74} Meta_w {17 75} Meta_W {17 76} Meta_Control_w {17 77} Meta_Control_w {17 78} Meta_Control_w {17 79} Meta_Control_w {17 80} W {17 81} w {17 82} W {17 83} w {17 84} Control_w {17 85} Control_w {17 86} Control_w {17 87} Control_w {17 88} Meta_w {17 89} Meta_W {17 90} Meta_w {17 91} Meta_W {17 92} Meta_Control_w {17 93} Meta_Control_w {17 94} Meta_Control_w {17 95} Meta_Control_w {17 96} W {17 97} w {17 98} W {17 99} w {17 100} Control_w {17 101} Control_w {17 102} Control_w {17 103} Control_w {17 104} Meta_w {17 105} Meta_W {17 106} Meta_w {17 107} Meta_W {17 108} Meta_Control_w {17 109} Meta_Control_w {17 110} Meta_Control_w {17 111} Meta_Control_w {17 112} W {17 113} w {17 114} W {17 115} w {17 116} Control_w {17 117} Control_w {17 118} Control_w {17 119} Control_w {17 120} Meta_w {17 121} Meta_W {17 122} Meta_w {17 123} Meta_W {17 124} Meta_Control_w {17 125} Meta_Control_w {17 126} Meta_Control_w {17 127} Meta_Control_w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} Control_e {18 5} Control_e {18 6} Control_e {18 7} Control_e {18 8} Meta_e {18 9} Meta_E {18 10} Meta_e {18 11} Meta_E {18 12} Meta_Control_e {18 13} Meta_Control_e {18 14} Meta_Control_e {18 15} Meta_Control_e {18 16} e {18 17} E {18 18} e {18 19} E {18 20} Control_e {18 21} Control_e {18 22} Control_e {18 23} Control_e {18 24} Meta_e {18 25} Meta_E {18 26} Meta_e {18 27} Meta_E {18 28} Meta_Control_e {18 29} Meta_Control_e {18 30} Meta_Control_e {18 31} Meta_Control_e {18 32} e {18 33} E {18 34} e {18 35} E {18 36} Control_e {18 37} Control_e {18 38} Control_e {18 39} Control_e {18 40} Meta_e {18 41} Meta_E {18 42} Meta_e {18 43} Meta_E {18 44} Meta_Control_e {18 45} Meta_Control_e {18 46} Meta_Control_e {18 47} Meta_Control_e {18 48} e {18 49} E {18 50} e {18 51} E {18 52} Control_e {18 53} Control_e {18 54} Control_e {18 55} Control_e {18 56} Meta_e {18 57} Meta_E {18 58} Meta_e {18 59} Meta_E {18 60} Meta_Control_e {18 61} Meta_Control_e {18 62} Meta_Control_e {18 63} Meta_Control_e {18 64} E {18 65} e {18 66} E {18 67} e {18 68} Control_e {18 69} Control_e {18 70} Control_e {18 71} Control_e {18 72} Meta_e {18 73} Meta_E {18 74} Meta_e {18 75} Meta_E {18 76} Meta_Control_e {18 77} Meta_Control_e {18 78} Meta_Control_e {18 79} Meta_Control_e {18 80} E {18 81} e {18 82} E {18 83} e {18 84} Control_e {18 85} Control_e {18 86} Control_e {18 87} Control_e {18 88} Meta_e {18 89} Meta_E {18 90} Meta_e {18 91} Meta_E {18 92} Meta_Control_e {18 93} Meta_Control_e {18 94} Meta_Control_e {18 95} Meta_Control_e {18 96} E {18 97} e {18 98} E {18 99} e {18 100} Control_e {18 101} Control_e {18 102} Control_e {18 103} Control_e {18 104} Meta_e {18 105} Meta_E {18 106} Meta_e {18 107} Meta_E {18 108} Meta_Control_e {18 109} Meta_Control_e {18 110} Meta_Control_e {18 111} Meta_Control_e {18 112} E {18 113} e {18 114} E {18 115} e {18 116} Control_e {18 117} Control_e {18 118} Control_e {18 119} Control_e {18 120} Meta_e {18 121} Meta_E {18 122} Meta_e {18 123} Meta_E {18 124} Meta_Control_e {18 125} Meta_Control_e {18 126} Meta_Control_e {18 127} Meta_Control_e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} Control_r {19 5} Control_r {19 6} Control_r {19 7} Control_r {19 8} Meta_r {19 9} Meta_R {19 10} Meta_r {19 11} Meta_R {19 12} Meta_Control_r {19 13} Meta_Control_r {19 14} Meta_Control_r {19 15} Meta_Control_r {19 16} r {19 17} R {19 18} r {19 19} R {19 20} Control_r {19 21} Control_r {19 22} Control_r {19 23} Control_r {19 24} Meta_r {19 25} Meta_R {19 26} Meta_r {19 27} Meta_R {19 28} Meta_Control_r {19 29} Meta_Control_r {19 30} Meta_Control_r {19 31} Meta_Control_r {19 32} r {19 33} R {19 34} r {19 35} R {19 36} Control_r {19 37} Control_r {19 38} Control_r {19 39} Control_r {19 40} Meta_r {19 41} Meta_R {19 42} Meta_r {19 43} Meta_R {19 44} Meta_Control_r {19 45} Meta_Control_r {19 46} Meta_Control_r {19 47} Meta_Control_r {19 48} r {19 49} R {19 50} r {19 51} R {19 52} Control_r {19 53} Control_r {19 54} Control_r {19 55} Control_r {19 56} Meta_r {19 57} Meta_R {19 58} Meta_r {19 59} Meta_R {19 60} Meta_Control_r {19 61} Meta_Control_r {19 62} Meta_Control_r {19 63} Meta_Control_r {19 64} R {19 65} r {19 66} R {19 67} r {19 68} Control_r {19 69} Control_r {19 70} Control_r {19 71} Control_r {19 72} Meta_r {19 73} Meta_R {19 74} Meta_r {19 75} Meta_R {19 76} Meta_Control_r {19 77} Meta_Control_r {19 78} Meta_Control_r {19 79} Meta_Control_r {19 80} R {19 81} r {19 82} R {19 83} r {19 84} Control_r {19 85} Control_r {19 86} Control_r {19 87} Control_r {19 88} Meta_r {19 89} Meta_R {19 90} Meta_r {19 91} Meta_R {19 92} Meta_Control_r {19 93} Meta_Control_r {19 94} Meta_Control_r {19 95} Meta_Control_r {19 96} R {19 97} r {19 98} R {19 99} r {19 100} Control_r {19 101} Control_r {19 102} Control_r {19 103} Control_r {19 104} Meta_r {19 105} Meta_R {19 106} Meta_r {19 107} Meta_R {19 108} Meta_Control_r {19 109} Meta_Control_r {19 110} Meta_Control_r {19 111} Meta_Control_r {19 112} R {19 113} r {19 114} R {19 115} r {19 116} Control_r {19 117} Control_r {19 118} Control_r {19 119} Control_r {19 120} Meta_r {19 121} Meta_R {19 122} Meta_r {19 123} Meta_R {19 124} Meta_Control_r {19 125} Meta_Control_r {19 126} Meta_Control_r {19 127} Meta_Control_r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} Control_t {20 5} Control_t {20 6} Control_t {20 7} Control_t {20 8} Meta_t {20 9} Meta_T {20 10} Meta_t {20 11} Meta_T {20 12} Meta_Control_t {20 13} Meta_Control_t {20 14} Meta_Control_t {20 15} Meta_Control_t {20 16} t {20 17} T {20 18} t {20 19} T {20 20} Control_t {20 21} Control_t {20 22} Control_t {20 23} Control_t {20 24} Meta_t {20 25} Meta_T {20 26} Meta_t {20 27} Meta_T {20 28} Meta_Control_t {20 29} Meta_Control_t {20 30} Meta_Control_t {20 31} Meta_Control_t {20 32} t {20 33} T {20 34} t {20 35} T {20 36} Control_t {20 37} Control_t {20 38} Control_t {20 39} Control_t {20 40} Meta_t {20 41} Meta_T {20 42} Meta_t {20 43} Meta_T {20 44} Meta_Control_t {20 45} Meta_Control_t {20 46} Meta_Control_t {20 47} Meta_Control_t {20 48} t {20 49} T {20 50} t {20 51} T {20 52} Control_t {20 53} Control_t {20 54} Control_t {20 55} Control_t {20 56} Meta_t {20 57} Meta_T {20 58} Meta_t {20 59} Meta_T {20 60} Meta_Control_t {20 61} Meta_Control_t {20 62} Meta_Control_t {20 63} Meta_Control_t {20 64} T {20 65} t {20 66} T {20 67} t {20 68} Control_t {20 69} Control_t {20 70} Control_t {20 71} Control_t {20 72} Meta_t {20 73} Meta_T {20 74} Meta_t {20 75} Meta_T {20 76} Meta_Control_t {20 77} Meta_Control_t {20 78} Meta_Control_t {20 79} Meta_Control_t {20 80} T {20 81} t {20 82} T {20 83} t {20 84} Control_t {20 85} Control_t {20 86} Control_t {20 87} Control_t {20 88} Meta_t {20 89} Meta_T {20 90} Meta_t {20 91} Meta_T {20 92} Meta_Control_t {20 93} Meta_Control_t {20 94} Meta_Control_t {20 95} Meta_Control_t {20 96} T {20 97} t {20 98} T {20 99} t {20 100} Control_t {20 101} Control_t {20 102} Control_t {20 103} Control_t {20 104} Meta_t {20 105} Meta_T {20 106} Meta_t {20 107} Meta_T {20 108} Meta_Control_t {20 109} Meta_Control_t {20 110} Meta_Control_t {20 111} Meta_Control_t {20 112} T {20 113} t {20 114} T {20 115} t {20 116} Control_t {20 117} Control_t {20 118} Control_t {20 119} Control_t {20 120} Meta_t {20 121} Meta_T {20 122} Meta_t {20 123} Meta_T {20 124} Meta_Control_t {20 125} Meta_Control_t {20 126} Meta_Control_t {20 127} Meta_Control_t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} Control_y {21 5} Control_y {21 6} Control_y {21 7} Control_y {21 8} Meta_y {21 9} Meta_Y {21 10} Meta_y {21 11} Meta_Y {21 12} Meta_Control_y {21 13} Meta_Control_y {21 14} Meta_Control_y {21 15} Meta_Control_y {21 16} y {21 17} Y {21 18} y {21 19} Y {21 20} Control_y {21 21} Control_y {21 22} Control_y {21 23} Control_y {21 24} Meta_y {21 25} Meta_Y {21 26} Meta_y {21 27} Meta_Y {21 28} Meta_Control_y {21 29} Meta_Control_y {21 30} Meta_Control_y {21 31} Meta_Control_y {21 32} y {21 33} Y {21 34} y {21 35} Y {21 36} Control_y {21 37} Control_y {21 38} Control_y {21 39} Control_y {21 40} Meta_y {21 41} Meta_Y {21 42} Meta_y {21 43} Meta_Y {21 44} Meta_Control_y {21 45} Meta_Control_y {21 46} Meta_Control_y {21 47} Meta_Control_y {21 48} y {21 49} Y {21 50} y {21 51} Y {21 52} Control_y {21 53} Control_y {21 54} Control_y {21 55} Control_y {21 56} Meta_y {21 57} Meta_Y {21 58} Meta_y {21 59} Meta_Y {21 60} Meta_Control_y {21 61} Meta_Control_y {21 62} Meta_Control_y {21 63} Meta_Control_y {21 64} Y {21 65} y {21 66} Y {21 67} y {21 68} Control_y {21 69} Control_y {21 70} Control_y {21 71} Control_y {21 72} Meta_y {21 73} Meta_Y {21 74} Meta_y {21 75} Meta_Y {21 76} Meta_Control_y {21 77} Meta_Control_y {21 78} Meta_Control_y {21 79} Meta_Control_y {21 80} Y {21 81} y {21 82} Y {21 83} y {21 84} Control_y {21 85} Control_y {21 86} Control_y {21 87} Control_y {21 88} Meta_y {21 89} Meta_Y {21 90} Meta_y {21 91} Meta_Y {21 92} Meta_Control_y {21 93} Meta_Control_y {21 94} Meta_Control_y {21 95} Meta_Control_y {21 96} Y {21 97} y {21 98} Y {21 99} y {21 100} Control_y {21 101} Control_y {21 102} Control_y {21 103} Control_y {21 104} Meta_y {21 105} Meta_Y {21 106} Meta_y {21 107} Meta_Y {21 108} Meta_Control_y {21 109} Meta_Control_y {21 110} Meta_Control_y {21 111} Meta_Control_y {21 112} Y {21 113} y {21 114} Y {21 115} y {21 116} Control_y {21 117} Control_y {21 118} Control_y {21 119} Control_y {21 120} Meta_y {21 121} Meta_Y {21 122} Meta_y {21 123} Meta_Y {21 124} Meta_Control_y {21 125} Meta_Control_y {21 126} Meta_Control_y {21 127} Meta_Control_y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} Control_u {22 5} Control_u {22 6} Control_u {22 7} Control_u {22 8} Meta_u {22 9} Meta_U {22 10} Meta_u {22 11} Meta_U {22 12} Meta_Control_u {22 13} Meta_Control_u {22 14} Meta_Control_u {22 15} Meta_Control_u {22 16} u {22 17} U {22 18} u {22 19} U {22 20} Control_u {22 21} Control_u {22 22} Control_u {22 23} Control_u {22 24} Meta_u {22 25} Meta_U {22 26} Meta_u {22 27} Meta_U {22 28} Meta_Control_u {22 29} Meta_Control_u {22 30} Meta_Control_u {22 31} Meta_Control_u {22 32} u {22 33} U {22 34} u {22 35} U {22 36} Control_u {22 37} Control_u {22 38} Control_u {22 39} Control_u {22 40} Meta_u {22 41} Meta_U {22 42} Meta_u {22 43} Meta_U {22 44} Meta_Control_u {22 45} Meta_Control_u {22 46} Meta_Control_u {22 47} Meta_Control_u {22 48} u {22 49} U {22 50} u {22 51} U {22 52} Control_u {22 53} Control_u {22 54} Control_u {22 55} Control_u {22 56} Meta_u {22 57} Meta_U {22 58} Meta_u {22 59} Meta_U {22 60} Meta_Control_u {22 61} Meta_Control_u {22 62} Meta_Control_u {22 63} Meta_Control_u {22 64} U {22 65} u {22 66} U {22 67} u {22 68} Control_u {22 69} Control_u {22 70} Control_u {22 71} Control_u {22 72} Meta_u {22 73} Meta_U {22 74} Meta_u {22 75} Meta_U {22 76} Meta_Control_u {22 77} Meta_Control_u {22 78} Meta_Control_u {22 79} Meta_Control_u {22 80} U {22 81} u {22 82} U {22 83} u {22 84} Control_u {22 85} Control_u {22 86} Control_u {22 87} Control_u {22 88} Meta_u {22 89} Meta_U {22 90} Meta_u {22 91} Meta_U {22 92} Meta_Control_u {22 93} Meta_Control_u {22 94} Meta_Control_u {22 95} Meta_Control_u {22 96} U {22 97} u {22 98} U {22 99} u {22 100} Control_u {22 101} Control_u {22 102} Control_u {22 103} Control_u {22 104} Meta_u {22 105} Meta_U {22 106} Meta_u {22 107} Meta_U {22 108} Meta_Control_u {22 109} Meta_Control_u {22 110} Meta_Control_u {22 111} Meta_Control_u {22 112} U {22 113} u {22 114} U {22 115} u {22 116} Control_u {22 117} Control_u {22 118} Control_u {22 119} Control_u {22 120} Meta_u {22 121} Meta_U {22 122} Meta_u {22 123} Meta_U {22 124} Meta_Control_u {22 125} Meta_Control_u {22 126} Meta_Control_u {22 127} Meta_Control_u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} Tab {23 5} Tab {23 6} Tab {23 7} Tab {23 8} Meta_i {23 9} Meta_I {23 10} Meta_i {23 11} Meta_I {23 12} Meta_Tab {23 13} Meta_Tab {23 14} Meta_Tab {23 15} Meta_Tab {23 16} i {23 17} I {23 18} i {23 19} I {23 20} Tab {23 21} Tab {23 22} Tab {23 23} Tab {23 24} Meta_i {23 25} Meta_I {23 26} Meta_i {23 27} Meta_I {23 28} Meta_Tab {23 29} Meta_Tab {23 30} Meta_Tab {23 31} Meta_Tab {23 32} i {23 33} I {23 34} i {23 35} I {23 36} Tab {23 37} Tab {23 38} Tab {23 39} Tab {23 40} Meta_i {23 41} Meta_I {23 42} Meta_i {23 43} Meta_I {23 44} Meta_Tab {23 45} Meta_Tab {23 46} Meta_Tab {23 47} Meta_Tab {23 48} i {23 49} I {23 50} i {23 51} I {23 52} Tab {23 53} Tab {23 54} Tab {23 55} Tab {23 56} Meta_i {23 57} Meta_I {23 58} Meta_i {23 59} Meta_I {23 60} Meta_Tab {23 61} Meta_Tab {23 62} Meta_Tab {23 63} Meta_Tab {23 64} I {23 65} i {23 66} I {23 67} i {23 68} Tab {23 69} Tab {23 70} Tab {23 71} Tab {23 72} Meta_i {23 73} Meta_I {23 74} Meta_i {23 75} Meta_I {23 76} Meta_Tab {23 77} Meta_Tab {23 78} Meta_Tab {23 79} Meta_Tab {23 80} I {23 81} i {23 82} I {23 83} i {23 84} Tab {23 85} Tab {23 86} Tab {23 87} Tab {23 88} Meta_i {23 89} Meta_I {23 90} Meta_i {23 91} Meta_I {23 92} Meta_Tab {23 93} Meta_Tab {23 94} Meta_Tab {23 95} Meta_Tab {23 96} I {23 97} i {23 98} I {23 99} i {23 100} Tab {23 101} Tab {23 102} Tab {23 103} Tab {23 104} Meta_i {23 105} Meta_I {23 106} Meta_i {23 107} Meta_I {23 108} Meta_Tab {23 109} Meta_Tab {23 110} Meta_Tab {23 111} Meta_Tab {23 112} I {23 113} i {23 114} I {23 115} i {23 116} Tab {23 117} Tab {23 118} Tab {23 119} Tab {23 120} Meta_i {23 121} Meta_I {23 122} Meta_i {23 123} Meta_I {23 124} Meta_Tab {23 125} Meta_Tab {23 126} Meta_Tab {23 127} Meta_Tab {24 0} o {24 1} O {24 2} o {24 3} O {24 4} Control_o {24 5} Control_o {24 6} Control_o {24 7} Control_o {24 8} Meta_o {24 9} Meta_O {24 10} Meta_o {24 11} Meta_O {24 12} Meta_Control_o {24 13} Meta_Control_o {24 14} Meta_Control_o {24 15} Meta_Control_o {24 16} o {24 17} O {24 18} o {24 19} O {24 20} Control_o {24 21} Control_o {24 22} Control_o {24 23} Control_o {24 24} Meta_o {24 25} Meta_O {24 26} Meta_o {24 27} Meta_O {24 28} Meta_Control_o {24 29} Meta_Control_o {24 30} Meta_Control_o {24 31} Meta_Control_o {24 32} o {24 33} O {24 34} o {24 35} O {24 36} Control_o {24 37} Control_o {24 38} Control_o {24 39} Control_o {24 40} Meta_o {24 41} Meta_O {24 42} Meta_o {24 43} Meta_O {24 44} Meta_Control_o {24 45} Meta_Control_o {24 46} Meta_Control_o {24 47} Meta_Control_o {24 48} o {24 49} O {24 50} o {24 51} O {24 52} Control_o {24 53} Control_o {24 54} Control_o {24 55} Control_o {24 56} Meta_o {24 57} Meta_O {24 58} Meta_o {24 59} Meta_O {24 60} Meta_Control_o {24 61} Meta_Control_o {24 62} Meta_Control_o {24 63} Meta_Control_o {24 64} O {24 65} o {24 66} O {24 67} o {24 68} Control_o {24 69} Control_o {24 70} Control_o {24 71} Control_o {24 72} Meta_o {24 73} Meta_O {24 74} Meta_o {24 75} Meta_O {24 76} Meta_Control_o {24 77} Meta_Control_o {24 78} Meta_Control_o {24 79} Meta_Control_o {24 80} O {24 81} o {24 82} O {24 83} o {24 84} Control_o {24 85} Control_o {24 86} Control_o {24 87} Control_o {24 88} Meta_o {24 89} Meta_O {24 90} Meta_o {24 91} Meta_O {24 92} Meta_Control_o {24 93} Meta_Control_o {24 94} Meta_Control_o {24 95} Meta_Control_o {24 96} O {24 97} o {24 98} O {24 99} o {24 100} Control_o {24 101} Control_o {24 102} Control_o {24 103} Control_o {24 104} Meta_o {24 105} Meta_O {24 106} Meta_o {24 107} Meta_O {24 108} Meta_Control_o {24 109} Meta_Control_o {24 110} Meta_Control_o {24 111} Meta_Control_o {24 112} O {24 113} o {24 114} O {24 115} o {24 116} Control_o {24 117} Control_o {24 118} Control_o {24 119} Control_o {24 120} Meta_o {24 121} Meta_O {24 122} Meta_o {24 123} Meta_O {24 124} Meta_Control_o {24 125} Meta_Control_o {24 126} Meta_Control_o {24 127} Meta_Control_o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} Control_p {25 5} Control_p {25 6} Control_p {25 7} Control_p {25 8} Meta_p {25 9} Meta_P {25 10} Meta_p {25 11} Meta_P {25 12} Meta_Control_p {25 13} Meta_Control_p {25 14} Meta_Control_p {25 15} Meta_Control_p {25 16} p {25 17} P {25 18} p {25 19} P {25 20} Control_p {25 21} Control_p {25 22} Control_p {25 23} Control_p {25 24} Meta_p {25 25} Meta_P {25 26} Meta_p {25 27} Meta_P {25 28} Meta_Control_p {25 29} Meta_Control_p {25 30} Meta_Control_p {25 31} Meta_Control_p {25 32} p {25 33} P {25 34} p {25 35} P {25 36} Control_p {25 37} Control_p {25 38} Control_p {25 39} Control_p {25 40} Meta_p {25 41} Meta_P {25 42} Meta_p {25 43} Meta_P {25 44} Meta_Control_p {25 45} Meta_Control_p {25 46} Meta_Control_p {25 47} Meta_Control_p {25 48} p {25 49} P {25 50} p {25 51} P {25 52} Control_p {25 53} Control_p {25 54} Control_p {25 55} Control_p {25 56} Meta_p {25 57} Meta_P {25 58} Meta_p {25 59} Meta_P {25 60} Meta_Control_p {25 61} Meta_Control_p {25 62} Meta_Control_p {25 63} Meta_Control_p {25 64} P {25 65} p {25 66} P {25 67} p {25 68} Control_p {25 69} Control_p {25 70} Control_p {25 71} Control_p {25 72} Meta_p {25 73} Meta_P {25 74} Meta_p {25 75} Meta_P {25 76} Meta_Control_p {25 77} Meta_Control_p {25 78} Meta_Control_p {25 79} Meta_Control_p {25 80} P {25 81} p {25 82} P {25 83} p {25 84} Control_p {25 85} Control_p {25 86} Control_p {25 87} Control_p {25 88} Meta_p {25 89} Meta_P {25 90} Meta_p {25 91} Meta_P {25 92} Meta_Control_p {25 93} Meta_Control_p {25 94} Meta_Control_p {25 95} Meta_Control_p {25 96} P {25 97} p {25 98} P {25 99} p {25 100} Control_p {25 101} Control_p {25 102} Control_p {25 103} Control_p {25 104} Meta_p {25 105} Meta_P {25 106} Meta_p {25 107} Meta_P {25 108} Meta_Control_p {25 109} Meta_Control_p {25 110} Meta_Control_p {25 111} Meta_Control_p {25 112} P {25 113} p {25 114} P {25 115} p {25 116} Control_p {25 117} Control_p {25 118} Control_p {25 119} Control_p {25 120} Meta_p {25 121} Meta_P {25 122} Meta_p {25 123} Meta_P {25 124} Meta_Control_p {25 125} Meta_Control_p {25 126} Meta_Control_p {25 127} Meta_Control_p {26 0} bracketleft {26 1} braceleft {26 2} bracketleft {26 3} braceleft {26 4} Escape {26 5} Escape {26 6} Escape {26 7} Escape {26 8} Meta_bracketleft {26 9} Meta_braceleft {26 10} Meta_bracketleft {26 11} Meta_braceleft {26 12} Meta_Escape {26 13} Meta_Escape {26 14} Meta_Escape {26 15} Meta_Escape {26 16} bracketleft {26 17} braceleft {26 18} bracketleft {26 19} braceleft {26 20} Escape {26 21} Escape {26 22} Escape {26 23} Escape {26 24} Meta_bracketleft {26 25} Meta_braceleft {26 26} Meta_bracketleft {26 27} Meta_braceleft {26 28} Meta_Escape {26 29} Meta_Escape {26 30} Meta_Escape {26 31} Meta_Escape {26 32} bracketleft {26 33} braceleft {26 34} bracketleft {26 35} braceleft {26 36} Escape {26 37} Escape {26 38} Escape {26 39} Escape {26 40} Meta_bracketleft {26 41} Meta_braceleft {26 42} Meta_bracketleft {26 43} Meta_braceleft {26 44} Meta_Escape {26 45} Meta_Escape {26 46} Meta_Escape {26 47} Meta_Escape {26 48} bracketleft {26 49} braceleft {26 50} bracketleft {26 51} braceleft {26 52} Escape {26 53} Escape {26 54} Escape {26 55} Escape {26 56} Meta_bracketleft {26 57} Meta_braceleft {26 58} Meta_bracketleft {26 59} Meta_braceleft {26 60} Meta_Escape {26 61} Meta_Escape {26 62} Meta_Escape {26 63} Meta_Escape {26 64} bracketleft {26 65} braceleft {26 66} bracketleft {26 67} braceleft {26 68} Escape {26 69} Escape {26 70} Escape {26 71} Escape {26 72} Meta_bracketleft {26 73} Meta_braceleft {26 74} Meta_bracketleft {26 75} Meta_braceleft {26 76} Meta_Escape {26 77} Meta_Escape {26 78} Meta_Escape {26 79} Meta_Escape {26 80} bracketleft {26 81} braceleft {26 82} bracketleft {26 83} braceleft {26 84} Escape {26 85} Escape {26 86} Escape {26 87} Escape {26 88} Meta_bracketleft {26 89} Meta_braceleft {26 90} Meta_bracketleft {26 91} Meta_braceleft {26 92} Meta_Escape {26 93} Meta_Escape {26 94} Meta_Escape {26 95} Meta_Escape {26 96} bracketleft {26 97} braceleft {26 98} bracketleft {26 99} braceleft {26 100} Escape {26 101} Escape {26 102} Escape {26 103} Escape {26 104} Meta_bracketleft {26 105} Meta_braceleft {26 106} Meta_bracketleft {26 107} Meta_braceleft {26 108} Meta_Escape {26 109} Meta_Escape {26 110} Meta_Escape {26 111} Meta_Escape {26 112} bracketleft {26 113} braceleft {26 114} bracketleft {26 115} braceleft {26 116} Escape {26 117} Escape {26 118} Escape {26 119} Escape {26 120} Meta_bracketleft {26 121} Meta_braceleft {26 122} Meta_bracketleft {26 123} Meta_braceleft {26 124} Meta_Escape {26 125} Meta_Escape {26 126} Meta_Escape {26 127} Meta_Escape {27 0} bracketright {27 1} braceright {27 2} bracketright {27 3} braceright {27 4} Control_bracketright {27 5} Control_bracketright {27 6} Control_bracketright {27 7} Control_bracketright {27 8} Meta_bracketright {27 9} Meta_braceright {27 10} Meta_bracketright {27 11} Meta_braceright {27 12} Meta_Control_bracketright {27 13} Meta_Control_bracketright {27 14} Meta_Control_bracketright {27 15} Meta_Control_bracketright {27 16} bracketright {27 17} braceright {27 18} bracketright {27 19} braceright {27 20} Control_bracketright {27 21} Control_bracketright {27 22} Control_bracketright {27 23} Control_bracketright {27 24} Meta_bracketright {27 25} Meta_braceright {27 26} Meta_bracketright {27 27} Meta_braceright {27 28} Meta_Control_bracketright {27 29} Meta_Control_bracketright {27 30} Meta_Control_bracketright {27 31} Meta_Control_bracketright {27 32} bracketright {27 33} braceright {27 34} bracketright {27 35} braceright {27 36} Control_bracketright {27 37} Control_bracketright {27 38} Control_bracketright {27 39} Control_bracketright {27 40} Meta_bracketright {27 41} Meta_braceright {27 42} Meta_bracketright {27 43} Meta_braceright {27 44} Meta_Control_bracketright {27 45} Meta_Control_bracketright {27 46} Meta_Control_bracketright {27 47} Meta_Control_bracketright {27 48} bracketright {27 49} braceright {27 50} bracketright {27 51} braceright {27 52} Control_bracketright {27 53} Control_bracketright {27 54} Control_bracketright {27 55} Control_bracketright {27 56} Meta_bracketright {27 57} Meta_braceright {27 58} Meta_bracketright {27 59} Meta_braceright {27 60} Meta_Control_bracketright {27 61} Meta_Control_bracketright {27 62} Meta_Control_bracketright {27 63} Meta_Control_bracketright {27 64} bracketright {27 65} braceright {27 66} bracketright {27 67} braceright {27 68} Control_bracketright {27 69} Control_bracketright {27 70} Control_bracketright {27 71} Control_bracketright {27 72} Meta_bracketright {27 73} Meta_braceright {27 74} Meta_bracketright {27 75} Meta_braceright {27 76} Meta_Control_bracketright {27 77} Meta_Control_bracketright {27 78} Meta_Control_bracketright {27 79} Meta_Control_bracketright {27 80} bracketright {27 81} braceright {27 82} bracketright {27 83} braceright {27 84} Control_bracketright {27 85} Control_bracketright {27 86} Control_bracketright {27 87} Control_bracketright {27 88} Meta_bracketright {27 89} Meta_braceright {27 90} Meta_bracketright {27 91} Meta_braceright {27 92} Meta_Control_bracketright {27 93} Meta_Control_bracketright {27 94} Meta_Control_bracketright {27 95} Meta_Control_bracketright {27 96} bracketright {27 97} braceright {27 98} bracketright {27 99} braceright {27 100} Control_bracketright {27 101} Control_bracketright {27 102} Control_bracketright {27 103} Control_bracketright {27 104} Meta_bracketright {27 105} Meta_braceright {27 106} Meta_bracketright {27 107} Meta_braceright {27 108} Meta_Control_bracketright {27 109} Meta_Control_bracketright {27 110} Meta_Control_bracketright {27 111} Meta_Control_bracketright {27 112} bracketright {27 113} braceright {27 114} bracketright {27 115} braceright {27 116} Control_bracketright {27 117} Control_bracketright {27 118} Control_bracketright {27 119} Control_bracketright {27 120} Meta_bracketright {27 121} Meta_braceright {27 122} Meta_bracketright {27 123} Meta_braceright {27 124} Meta_Control_bracketright {27 125} Meta_Control_bracketright {27 126} Meta_Control_bracketright {27 127} Meta_Control_bracketright {28 0} Return {28 1} Return {28 2} Return {28 3} Return {28 4} Control_m {28 5} Control_m {28 6} Control_m {28 7} Control_m {28 8} Meta_Control_m {28 9} Meta_Control_m {28 10} Meta_Control_m {28 11} Meta_Control_m {28 12} Meta_Control_m {28 13} Meta_Control_m {28 14} Meta_Control_m {28 15} Meta_Control_m {28 16} Return {28 17} Return {28 18} Return {28 19} Return {28 20} Control_m {28 21} Control_m {28 22} Control_m {28 23} Control_m {28 24} Meta_Control_m {28 25} Meta_Control_m {28 26} Meta_Control_m {28 27} Meta_Control_m {28 28} Meta_Control_m {28 29} Meta_Control_m {28 30} Meta_Control_m {28 31} Meta_Control_m {28 32} Return {28 33} Return {28 34} Return {28 35} Return {28 36} Control_m {28 37} Control_m {28 38} Control_m {28 39} Control_m {28 40} Meta_Control_m {28 41} Meta_Control_m {28 42} Meta_Control_m {28 43} Meta_Control_m {28 44} Meta_Control_m {28 45} Meta_Control_m {28 46} Meta_Control_m {28 47} Meta_Control_m {28 48} Return {28 49} Return {28 50} Return {28 51} Return {28 52} Control_m {28 53} Control_m {28 54} Control_m {28 55} Control_m {28 56} Meta_Control_m {28 57} Meta_Control_m {28 58} Meta_Control_m {28 59} Meta_Control_m {28 60} Meta_Control_m {28 61} Meta_Control_m {28 62} Meta_Control_m {28 63} Meta_Control_m {28 64} Return {28 65} Return {28 66} Return {28 67} Return {28 68} Control_m {28 69} Control_m {28 70} Control_m {28 71} Control_m {28 72} Meta_Control_m {28 73} Meta_Control_m {28 74} Meta_Control_m {28 75} Meta_Control_m {28 76} Meta_Control_m {28 77} Meta_Control_m {28 78} Meta_Control_m {28 79} Meta_Control_m {28 80} Return {28 81} Return {28 82} Return {28 83} Return {28 84} Control_m {28 85} Control_m {28 86} Control_m {28 87} Control_m {28 88} Meta_Control_m {28 89} Meta_Control_m {28 90} Meta_Control_m {28 91} Meta_Control_m {28 92} Meta_Control_m {28 93} Meta_Control_m {28 94} Meta_Control_m {28 95} Meta_Control_m {28 96} Return {28 97} Return {28 98} Return {28 99} Return {28 100} Control_m {28 101} Control_m {28 102} Control_m {28 103} Control_m {28 104} Meta_Control_m {28 105} Meta_Control_m {28 106} Meta_Control_m {28 107} Meta_Control_m {28 108} Meta_Control_m {28 109} Meta_Control_m {28 110} Meta_Control_m {28 111} Meta_Control_m {28 112} Return {28 113} Return {28 114} Return {28 115} Return {28 116} Control_m {28 117} Control_m {28 118} Control_m {28 119} Control_m {28 120} Meta_Control_m {28 121} Meta_Control_m {28 122} Meta_Control_m {28 123} Meta_Control_m {28 124} Meta_Control_m {28 125} Meta_Control_m {28 126} Meta_Control_m {28 127} Meta_Control_m {29 0} Control {29 1} Control {29 2} Control {29 3} Control {29 4} Control {29 5} Control {29 6} Control {29 7} Control {29 8} Control {29 9} Control {29 10} Control {29 11} Control {29 12} Control {29 13} Control {29 14} Control {29 15} Control {29 16} Control {29 17} Control {29 18} Control {29 19} Control {29 20} Control {29 21} Control {29 22} Control {29 23} Control {29 24} Control {29 25} Control {29 26} Control {29 27} Control {29 28} Control {29 29} Control {29 30} Control {29 31} Control {29 32} Control {29 33} Control {29 34} Control {29 35} Control {29 36} Control {29 37} Control {29 38} Control {29 39} Control {29 40} Control {29 41} Control {29 42} Control {29 43} Control {29 44} Control {29 45} Control {29 46} Control {29 47} Control {29 48} Control {29 49} Control {29 50} Control {29 51} Control {29 52} Control {29 53} Control {29 54} Control {29 55} Control {29 56} Control {29 57} Control {29 58} Control {29 59} Control {29 60} Control {29 61} Control {29 62} Control {29 63} Control {29 64} Control {29 65} Control {29 66} Control {29 67} Control {29 68} Control {29 69} Control {29 70} Control {29 71} Control {29 72} Control {29 73} Control {29 74} Control {29 75} Control {29 76} Control {29 77} Control {29 78} Control {29 79} Control {29 80} Control {29 81} Control {29 82} Control {29 83} Control {29 84} Control {29 85} Control {29 86} Control {29 87} Control {29 88} Control {29 89} Control {29 90} Control {29 91} Control {29 92} Control {29 93} Control {29 94} Control {29 95} Control {29 96} Control {29 97} Control {29 98} Control {29 99} Control {29 100} Control {29 101} Control {29 102} Control {29 103} Control {29 104} Control {29 105} Control {29 106} Control {29 107} Control {29 108} Control {29 109} Control {29 110} Control {29 111} Control {29 112} Control {29 113} Control {29 114} Control {29 115} Control {29 116} Control {29 117} Control {29 118} Control {29 119} Control {29 120} Control {29 121} Control {29 122} Control {29 123} Control {29 124} Control {29 125} Control {29 126} Control {29 127} Control {30 0} a {30 1} A {30 2} a {30 3} A {30 4} Control_a {30 5} Control_a {30 6} Control_a {30 7} Control_a {30 8} Meta_a {30 9} Meta_A {30 10} Meta_a {30 11} Meta_A {30 12} Meta_Control_a {30 13} Meta_Control_a {30 14} Meta_Control_a {30 15} Meta_Control_a {30 16} a {30 17} A {30 18} a {30 19} A {30 20} Control_a {30 21} Control_a {30 22} Control_a {30 23} Control_a {30 24} Meta_a {30 25} Meta_A {30 26} Meta_a {30 27} Meta_A {30 28} Meta_Control_a {30 29} Meta_Control_a {30 30} Meta_Control_a {30 31} Meta_Control_a {30 32} a {30 33} A {30 34} a {30 35} A {30 36} Control_a {30 37} Control_a {30 38} Control_a {30 39} Control_a {30 40} Meta_a {30 41} Meta_A {30 42} Meta_a {30 43} Meta_A {30 44} Meta_Control_a {30 45} Meta_Control_a {30 46} Meta_Control_a {30 47} Meta_Control_a {30 48} a {30 49} A {30 50} a {30 51} A {30 52} Control_a {30 53} Control_a {30 54} Control_a {30 55} Control_a {30 56} Meta_a {30 57} Meta_A {30 58} Meta_a {30 59} Meta_A {30 60} Meta_Control_a {30 61} Meta_Control_a {30 62} Meta_Control_a {30 63} Meta_Control_a {30 64} A {30 65} a {30 66} A {30 67} a {30 68} Control_a {30 69} Control_a {30 70} Control_a {30 71} Control_a {30 72} Meta_a {30 73} Meta_A {30 74} Meta_a {30 75} Meta_A {30 76} Meta_Control_a {30 77} Meta_Control_a {30 78} Meta_Control_a {30 79} Meta_Control_a {30 80} A {30 81} a {30 82} A {30 83} a {30 84} Control_a {30 85} Control_a {30 86} Control_a {30 87} Control_a {30 88} Meta_a {30 89} Meta_A {30 90} Meta_a {30 91} Meta_A {30 92} Meta_Control_a {30 93} Meta_Control_a {30 94} Meta_Control_a {30 95} Meta_Control_a {30 96} A {30 97} a {30 98} A {30 99} a {30 100} Control_a {30 101} Control_a {30 102} Control_a {30 103} Control_a {30 104} Meta_a {30 105} Meta_A {30 106} Meta_a {30 107} Meta_A {30 108} Meta_Control_a {30 109} Meta_Control_a {30 110} Meta_Control_a {30 111} Meta_Control_a {30 112} A {30 113} a {30 114} A {30 115} a {30 116} Control_a {30 117} Control_a {30 118} Control_a {30 119} Control_a {30 120} Meta_a {30 121} Meta_A {30 122} Meta_a {30 123} Meta_A {30 124} Meta_Control_a {30 125} Meta_Control_a {30 126} Meta_Control_a {30 127} Meta_Control_a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} Control_s {31 5} Control_s {31 6} Control_s {31 7} Control_s {31 8} Meta_s {31 9} Meta_S {31 10} Meta_s {31 11} Meta_S {31 12} Meta_Control_s {31 13} Meta_Control_s {31 14} Meta_Control_s {31 15} Meta_Control_s {31 16} s {31 17} S {31 18} s {31 19} S {31 20} Control_s {31 21} Control_s {31 22} Control_s {31 23} Control_s {31 24} Meta_s {31 25} Meta_S {31 26} Meta_s {31 27} Meta_S {31 28} Meta_Control_s {31 29} Meta_Control_s {31 30} Meta_Control_s {31 31} Meta_Control_s {31 32} s {31 33} S {31 34} s {31 35} S {31 36} Control_s {31 37} Control_s {31 38} Control_s {31 39} Control_s {31 40} Meta_s {31 41} Meta_S {31 42} Meta_s {31 43} Meta_S {31 44} Meta_Control_s {31 45} Meta_Control_s {31 46} Meta_Control_s {31 47} Meta_Control_s {31 48} s {31 49} S {31 50} s {31 51} S {31 52} Control_s {31 53} Control_s {31 54} Control_s {31 55} Control_s {31 56} Meta_s {31 57} Meta_S {31 58} Meta_s {31 59} Meta_S {31 60} Meta_Control_s {31 61} Meta_Control_s {31 62} Meta_Control_s {31 63} Meta_Control_s {31 64} S {31 65} s {31 66} S {31 67} s {31 68} Control_s {31 69} Control_s {31 70} Control_s {31 71} Control_s {31 72} Meta_s {31 73} Meta_S {31 74} Meta_s {31 75} Meta_S {31 76} Meta_Control_s {31 77} Meta_Control_s {31 78} Meta_Control_s {31 79} Meta_Control_s {31 80} S {31 81} s {31 82} S {31 83} s {31 84} Control_s {31 85} Control_s {31 86} Control_s {31 87} Control_s {31 88} Meta_s {31 89} Meta_S {31 90} Meta_s {31 91} Meta_S {31 92} Meta_Control_s {31 93} Meta_Control_s {31 94} Meta_Control_s {31 95} Meta_Control_s {31 96} S {31 97} s {31 98} S {31 99} s {31 100} Control_s {31 101} Control_s {31 102} Control_s {31 103} Control_s {31 104} Meta_s {31 105} Meta_S {31 106} Meta_s {31 107} Meta_S {31 108} Meta_Control_s {31 109} Meta_Control_s {31 110} Meta_Control_s {31 111} Meta_Control_s {31 112} S {31 113} s {31 114} S {31 115} s {31 116} Control_s {31 117} Control_s {31 118} Control_s {31 119} Control_s {31 120} Meta_s {31 121} Meta_S {31 122} Meta_s {31 123} Meta_S {31 124} Meta_Control_s {31 125} Meta_Control_s {31 126} Meta_Control_s {31 127} Meta_Control_s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} Control_d {32 5} Control_d {32 6} Control_d {32 7} Control_d {32 8} Meta_d {32 9} Meta_D {32 10} Meta_d {32 11} Meta_D {32 12} Meta_Control_d {32 13} Meta_Control_d {32 14} Meta_Control_d {32 15} Meta_Control_d {32 16} d {32 17} D {32 18} d {32 19} D {32 20} Control_d {32 21} Control_d {32 22} Control_d {32 23} Control_d {32 24} Meta_d {32 25} Meta_D {32 26} Meta_d {32 27} Meta_D {32 28} Meta_Control_d {32 29} Meta_Control_d {32 30} Meta_Control_d {32 31} Meta_Control_d {32 32} d {32 33} D {32 34} d {32 35} D {32 36} Control_d {32 37} Control_d {32 38} Control_d {32 39} Control_d {32 40} Meta_d {32 41} Meta_D {32 42} Meta_d {32 43} Meta_D {32 44} Meta_Control_d {32 45} Meta_Control_d {32 46} Meta_Control_d {32 47} Meta_Control_d {32 48} d {32 49} D {32 50} d {32 51} D {32 52} Control_d {32 53} Control_d {32 54} Control_d {32 55} Control_d {32 56} Meta_d {32 57} Meta_D {32 58} Meta_d {32 59} Meta_D {32 60} Meta_Control_d {32 61} Meta_Control_d {32 62} Meta_Control_d {32 63} Meta_Control_d {32 64} D {32 65} d {32 66} D {32 67} d {32 68} Control_d {32 69} Control_d {32 70} Control_d {32 71} Control_d {32 72} Meta_d {32 73} Meta_D {32 74} Meta_d {32 75} Meta_D {32 76} Meta_Control_d {32 77} Meta_Control_d {32 78} Meta_Control_d {32 79} Meta_Control_d {32 80} D {32 81} d {32 82} D {32 83} d {32 84} Control_d {32 85} Control_d {32 86} Control_d {32 87} Control_d {32 88} Meta_d {32 89} Meta_D {32 90} Meta_d {32 91} Meta_D {32 92} Meta_Control_d {32 93} Meta_Control_d {32 94} Meta_Control_d {32 95} Meta_Control_d {32 96} D {32 97} d {32 98} D {32 99} d {32 100} Control_d {32 101} Control_d {32 102} Control_d {32 103} Control_d {32 104} Meta_d {32 105} Meta_D {32 106} Meta_d {32 107} Meta_D {32 108} Meta_Control_d {32 109} Meta_Control_d {32 110} Meta_Control_d {32 111} Meta_Control_d {32 112} D {32 113} d {32 114} D {32 115} d {32 116} Control_d {32 117} Control_d {32 118} Control_d {32 119} Control_d {32 120} Meta_d {32 121} Meta_D {32 122} Meta_d {32 123} Meta_D {32 124} Meta_Control_d {32 125} Meta_Control_d {32 126} Meta_Control_d {32 127} Meta_Control_d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} Control_f {33 5} Control_f {33 6} Control_f {33 7} Control_f {33 8} Meta_f {33 9} Meta_F {33 10} Meta_f {33 11} Meta_F {33 12} Meta_Control_f {33 13} Meta_Control_f {33 14} Meta_Control_f {33 15} Meta_Control_f {33 16} f {33 17} F {33 18} f {33 19} F {33 20} Control_f {33 21} Control_f {33 22} Control_f {33 23} Control_f {33 24} Meta_f {33 25} Meta_F {33 26} Meta_f {33 27} Meta_F {33 28} Meta_Control_f {33 29} Meta_Control_f {33 30} Meta_Control_f {33 31} Meta_Control_f {33 32} f {33 33} F {33 34} f {33 35} F {33 36} Control_f {33 37} Control_f {33 38} Control_f {33 39} Control_f {33 40} Meta_f {33 41} Meta_F {33 42} Meta_f {33 43} Meta_F {33 44} Meta_Control_f {33 45} Meta_Control_f {33 46} Meta_Control_f {33 47} Meta_Control_f {33 48} f {33 49} F {33 50} f {33 51} F {33 52} Control_f {33 53} Control_f {33 54} Control_f {33 55} Control_f {33 56} Meta_f {33 57} Meta_F {33 58} Meta_f {33 59} Meta_F {33 60} Meta_Control_f {33 61} Meta_Control_f {33 62} Meta_Control_f {33 63} Meta_Control_f {33 64} F {33 65} f {33 66} F {33 67} f {33 68} Control_f {33 69} Control_f {33 70} Control_f {33 71} Control_f {33 72} Meta_f {33 73} Meta_F {33 74} Meta_f {33 75} Meta_F {33 76} Meta_Control_f {33 77} Meta_Control_f {33 78} Meta_Control_f {33 79} Meta_Control_f {33 80} F {33 81} f {33 82} F {33 83} f {33 84} Control_f {33 85} Control_f {33 86} Control_f {33 87} Control_f {33 88} Meta_f {33 89} Meta_F {33 90} Meta_f {33 91} Meta_F {33 92} Meta_Control_f {33 93} Meta_Control_f {33 94} Meta_Control_f {33 95} Meta_Control_f {33 96} F {33 97} f {33 98} F {33 99} f {33 100} Control_f {33 101} Control_f {33 102} Control_f {33 103} Control_f {33 104} Meta_f {33 105} Meta_F {33 106} Meta_f {33 107} Meta_F {33 108} Meta_Control_f {33 109} Meta_Control_f {33 110} Meta_Control_f {33 111} Meta_Control_f {33 112} F {33 113} f {33 114} F {33 115} f {33 116} Control_f {33 117} Control_f {33 118} Control_f {33 119} Control_f {33 120} Meta_f {33 121} Meta_F {33 122} Meta_f {33 123} Meta_F {33 124} Meta_Control_f {33 125} Meta_Control_f {33 126} Meta_Control_f {33 127} Meta_Control_f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} Control_g {34 5} Control_g {34 6} Control_g {34 7} Control_g {34 8} Meta_g {34 9} Meta_G {34 10} Meta_g {34 11} Meta_G {34 12} Meta_Control_g {34 13} Meta_Control_g {34 14} Meta_Control_g {34 15} Meta_Control_g {34 16} g {34 17} G {34 18} g {34 19} G {34 20} Control_g {34 21} Control_g {34 22} Control_g {34 23} Control_g {34 24} Meta_g {34 25} Meta_G {34 26} Meta_g {34 27} Meta_G {34 28} Meta_Control_g {34 29} Meta_Control_g {34 30} Meta_Control_g {34 31} Meta_Control_g {34 32} g {34 33} G {34 34} g {34 35} G {34 36} Control_g {34 37} Control_g {34 38} Control_g {34 39} Control_g {34 40} Meta_g {34 41} Meta_G {34 42} Meta_g {34 43} Meta_G {34 44} Meta_Control_g {34 45} Meta_Control_g {34 46} Meta_Control_g {34 47} Meta_Control_g {34 48} g {34 49} G {34 50} g {34 51} G {34 52} Control_g {34 53} Control_g {34 54} Control_g {34 55} Control_g {34 56} Meta_g {34 57} Meta_G {34 58} Meta_g {34 59} Meta_G {34 60} Meta_Control_g {34 61} Meta_Control_g {34 62} Meta_Control_g {34 63} Meta_Control_g {34 64} G {34 65} g {34 66} G {34 67} g {34 68} Control_g {34 69} Control_g {34 70} Control_g {34 71} Control_g {34 72} Meta_g {34 73} Meta_G {34 74} Meta_g {34 75} Meta_G {34 76} Meta_Control_g {34 77} Meta_Control_g {34 78} Meta_Control_g {34 79} Meta_Control_g {34 80} G {34 81} g {34 82} G {34 83} g {34 84} Control_g {34 85} Control_g {34 86} Control_g {34 87} Control_g {34 88} Meta_g {34 89} Meta_G {34 90} Meta_g {34 91} Meta_G {34 92} Meta_Control_g {34 93} Meta_Control_g {34 94} Meta_Control_g {34 95} Meta_Control_g {34 96} G {34 97} g {34 98} G {34 99} g {34 100} Control_g {34 101} Control_g {34 102} Control_g {34 103} Control_g {34 104} Meta_g {34 105} Meta_G {34 106} Meta_g {34 107} Meta_G {34 108} Meta_Control_g {34 109} Meta_Control_g {34 110} Meta_Control_g {34 111} Meta_Control_g {34 112} G {34 113} g {34 114} G {34 115} g {34 116} Control_g {34 117} Control_g {34 118} Control_g {34 119} Control_g {34 120} Meta_g {34 121} Meta_G {34 122} Meta_g {34 123} Meta_G {34 124} Meta_Control_g {34 125} Meta_Control_g {34 126} Meta_Control_g {34 127} Meta_Control_g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} BackSpace {35 5} BackSpace {35 6} BackSpace {35 7} BackSpace {35 8} Meta_h {35 9} Meta_H {35 10} Meta_h {35 11} Meta_H {35 12} Meta_BackSpace {35 13} Meta_BackSpace {35 14} Meta_BackSpace {35 15} Meta_BackSpace {35 16} h {35 17} H {35 18} h {35 19} H {35 20} BackSpace {35 21} BackSpace {35 22} BackSpace {35 23} BackSpace {35 24} Meta_h {35 25} Meta_H {35 26} Meta_h {35 27} Meta_H {35 28} Meta_BackSpace {35 29} Meta_BackSpace {35 30} Meta_BackSpace {35 31} Meta_BackSpace {35 32} h {35 33} H {35 34} h {35 35} H {35 36} BackSpace {35 37} BackSpace {35 38} BackSpace {35 39} BackSpace {35 40} Meta_h {35 41} Meta_H {35 42} Meta_h {35 43} Meta_H {35 44} Meta_BackSpace {35 45} Meta_BackSpace {35 46} Meta_BackSpace {35 47} Meta_BackSpace {35 48} h {35 49} H {35 50} h {35 51} H {35 52} BackSpace {35 53} BackSpace {35 54} BackSpace {35 55} BackSpace {35 56} Meta_h {35 57} Meta_H {35 58} Meta_h {35 59} Meta_H {35 60} Meta_BackSpace {35 61} Meta_BackSpace {35 62} Meta_BackSpace {35 63} Meta_BackSpace {35 64} H {35 65} h {35 66} H {35 67} h {35 68} BackSpace {35 69} BackSpace {35 70} BackSpace {35 71} BackSpace {35 72} Meta_h {35 73} Meta_H {35 74} Meta_h {35 75} Meta_H {35 76} Meta_BackSpace {35 77} Meta_BackSpace {35 78} Meta_BackSpace {35 79} Meta_BackSpace {35 80} H {35 81} h {35 82} H {35 83} h {35 84} BackSpace {35 85} BackSpace {35 86} BackSpace {35 87} BackSpace {35 88} Meta_h {35 89} Meta_H {35 90} Meta_h {35 91} Meta_H {35 92} Meta_BackSpace {35 93} Meta_BackSpace {35 94} Meta_BackSpace {35 95} Meta_BackSpace {35 96} H {35 97} h {35 98} H {35 99} h {35 100} BackSpace {35 101} BackSpace {35 102} BackSpace {35 103} BackSpace {35 104} Meta_h {35 105} Meta_H {35 106} Meta_h {35 107} Meta_H {35 108} Meta_BackSpace {35 109} Meta_BackSpace {35 110} Meta_BackSpace {35 111} Meta_BackSpace {35 112} H {35 113} h {35 114} H {35 115} h {35 116} BackSpace {35 117} BackSpace {35 118} BackSpace {35 119} BackSpace {35 120} Meta_h {35 121} Meta_H {35 122} Meta_h {35 123} Meta_H {35 124} Meta_BackSpace {35 125} Meta_BackSpace {35 126} Meta_BackSpace {35 127} Meta_BackSpace {36 0} j {36 1} J {36 2} j {36 3} J {36 4} Linefeed {36 5} Linefeed {36 6} Linefeed {36 7} Linefeed {36 8} Meta_j {36 9} Meta_J {36 10} Meta_j {36 11} Meta_J {36 12} Meta_Linefeed {36 13} Meta_Linefeed {36 14} Meta_Linefeed {36 15} Meta_Linefeed {36 16} j {36 17} J {36 18} j {36 19} J {36 20} Linefeed {36 21} Linefeed {36 22} Linefeed {36 23} Linefeed {36 24} Meta_j {36 25} Meta_J {36 26} Meta_j {36 27} Meta_J {36 28} Meta_Linefeed {36 29} Meta_Linefeed {36 30} Meta_Linefeed {36 31} Meta_Linefeed {36 32} j {36 33} J {36 34} j {36 35} J {36 36} Linefeed {36 37} Linefeed {36 38} Linefeed {36 39} Linefeed {36 40} Meta_j {36 41} Meta_J {36 42} Meta_j {36 43} Meta_J {36 44} Meta_Linefeed {36 45} Meta_Linefeed {36 46} Meta_Linefeed {36 47} Meta_Linefeed {36 48} j {36 49} J {36 50} j {36 51} J {36 52} Linefeed {36 53} Linefeed {36 54} Linefeed {36 55} Linefeed {36 56} Meta_j {36 57} Meta_J {36 58} Meta_j {36 59} Meta_J {36 60} Meta_Linefeed {36 61} Meta_Linefeed {36 62} Meta_Linefeed {36 63} Meta_Linefeed {36 64} J {36 65} j {36 66} J {36 67} j {36 68} Linefeed {36 69} Linefeed {36 70} Linefeed {36 71} Linefeed {36 72} Meta_j {36 73} Meta_J {36 74} Meta_j {36 75} Meta_J {36 76} Meta_Linefeed {36 77} Meta_Linefeed {36 78} Meta_Linefeed {36 79} Meta_Linefeed {36 80} J {36 81} j {36 82} J {36 83} j {36 84} Linefeed {36 85} Linefeed {36 86} Linefeed {36 87} Linefeed {36 88} Meta_j {36 89} Meta_J {36 90} Meta_j {36 91} Meta_J {36 92} Meta_Linefeed {36 93} Meta_Linefeed {36 94} Meta_Linefeed {36 95} Meta_Linefeed {36 96} J {36 97} j {36 98} J {36 99} j {36 100} Linefeed {36 101} Linefeed {36 102} Linefeed {36 103} Linefeed {36 104} Meta_j {36 105} Meta_J {36 106} Meta_j {36 107} Meta_J {36 108} Meta_Linefeed {36 109} Meta_Linefeed {36 110} Meta_Linefeed {36 111} Meta_Linefeed {36 112} J {36 113} j {36 114} J {36 115} j {36 116} Linefeed {36 117} Linefeed {36 118} Linefeed {36 119} Linefeed {36 120} Meta_j {36 121} Meta_J {36 122} Meta_j {36 123} Meta_J {36 124} Meta_Linefeed {36 125} Meta_Linefeed {36 126} Meta_Linefeed {36 127} Meta_Linefeed {37 0} k {37 1} K {37 2} k {37 3} K {37 4} Control_k {37 5} Control_k {37 6} Control_k {37 7} Control_k {37 8} Meta_k {37 9} Meta_K {37 10} Meta_k {37 11} Meta_K {37 12} Meta_Control_k {37 13} Meta_Control_k {37 14} Meta_Control_k {37 15} Meta_Control_k {37 16} k {37 17} K {37 18} k {37 19} K {37 20} Control_k {37 21} Control_k {37 22} Control_k {37 23} Control_k {37 24} Meta_k {37 25} Meta_K {37 26} Meta_k {37 27} Meta_K {37 28} Meta_Control_k {37 29} Meta_Control_k {37 30} Meta_Control_k {37 31} Meta_Control_k {37 32} k {37 33} K {37 34} k {37 35} K {37 36} Control_k {37 37} Control_k {37 38} Control_k {37 39} Control_k {37 40} Meta_k {37 41} Meta_K {37 42} Meta_k {37 43} Meta_K {37 44} Meta_Control_k {37 45} Meta_Control_k {37 46} Meta_Control_k {37 47} Meta_Control_k {37 48} k {37 49} K {37 50} k {37 51} K {37 52} Control_k {37 53} Control_k {37 54} Control_k {37 55} Control_k {37 56} Meta_k {37 57} Meta_K {37 58} Meta_k {37 59} Meta_K {37 60} Meta_Control_k {37 61} Meta_Control_k {37 62} Meta_Control_k {37 63} Meta_Control_k {37 64} K {37 65} k {37 66} K {37 67} k {37 68} Control_k {37 69} Control_k {37 70} Control_k {37 71} Control_k {37 72} Meta_k {37 73} Meta_K {37 74} Meta_k {37 75} Meta_K {37 76} Meta_Control_k {37 77} Meta_Control_k {37 78} Meta_Control_k {37 79} Meta_Control_k {37 80} K {37 81} k {37 82} K {37 83} k {37 84} Control_k {37 85} Control_k {37 86} Control_k {37 87} Control_k {37 88} Meta_k {37 89} Meta_K {37 90} Meta_k {37 91} Meta_K {37 92} Meta_Control_k {37 93} Meta_Control_k {37 94} Meta_Control_k {37 95} Meta_Control_k {37 96} K {37 97} k {37 98} K {37 99} k {37 100} Control_k {37 101} Control_k {37 102} Control_k {37 103} Control_k {37 104} Meta_k {37 105} Meta_K {37 106} Meta_k {37 107} Meta_K {37 108} Meta_Control_k {37 109} Meta_Control_k {37 110} Meta_Control_k {37 111} Meta_Control_k {37 112} K {37 113} k {37 114} K {37 115} k {37 116} Control_k {37 117} Control_k {37 118} Control_k {37 119} Control_k {37 120} Meta_k {37 121} Meta_K {37 122} Meta_k {37 123} Meta_K {37 124} Meta_Control_k {37 125} Meta_Control_k {37 126} Meta_Control_k {37 127} Meta_Control_k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} Control_l {38 5} Control_l {38 6} Control_l {38 7} Control_l {38 8} Meta_l {38 9} Meta_L {38 10} Meta_l {38 11} Meta_L {38 12} Meta_Control_l {38 13} Meta_Control_l {38 14} Meta_Control_l {38 15} Meta_Control_l {38 16} l {38 17} L {38 18} l {38 19} L {38 20} Control_l {38 21} Control_l {38 22} Control_l {38 23} Control_l {38 24} Meta_l {38 25} Meta_L {38 26} Meta_l {38 27} Meta_L {38 28} Meta_Control_l {38 29} Meta_Control_l {38 30} Meta_Control_l {38 31} Meta_Control_l {38 32} l {38 33} L {38 34} l {38 35} L {38 36} Control_l {38 37} Control_l {38 38} Control_l {38 39} Control_l {38 40} Meta_l {38 41} Meta_L {38 42} Meta_l {38 43} Meta_L {38 44} Meta_Control_l {38 45} Meta_Control_l {38 46} Meta_Control_l {38 47} Meta_Control_l {38 48} l {38 49} L {38 50} l {38 51} L {38 52} Control_l {38 53} Control_l {38 54} Control_l {38 55} Control_l {38 56} Meta_l {38 57} Meta_L {38 58} Meta_l {38 59} Meta_L {38 60} Meta_Control_l {38 61} Meta_Control_l {38 62} Meta_Control_l {38 63} Meta_Control_l {38 64} L {38 65} l {38 66} L {38 67} l {38 68} Control_l {38 69} Control_l {38 70} Control_l {38 71} Control_l {38 72} Meta_l {38 73} Meta_L {38 74} Meta_l {38 75} Meta_L {38 76} Meta_Control_l {38 77} Meta_Control_l {38 78} Meta_Control_l {38 79} Meta_Control_l {38 80} L {38 81} l {38 82} L {38 83} l {38 84} Control_l {38 85} Control_l {38 86} Control_l {38 87} Control_l {38 88} Meta_l {38 89} Meta_L {38 90} Meta_l {38 91} Meta_L {38 92} Meta_Control_l {38 93} Meta_Control_l {38 94} Meta_Control_l {38 95} Meta_Control_l {38 96} L {38 97} l {38 98} L {38 99} l {38 100} Control_l {38 101} Control_l {38 102} Control_l {38 103} Control_l {38 104} Meta_l {38 105} Meta_L {38 106} Meta_l {38 107} Meta_L {38 108} Meta_Control_l {38 109} Meta_Control_l {38 110} Meta_Control_l {38 111} Meta_Control_l {38 112} L {38 113} l {38 114} L {38 115} l {38 116} Control_l {38 117} Control_l {38 118} Control_l {38 119} Control_l {38 120} Meta_l {38 121} Meta_L {38 122} Meta_l {38 123} Meta_L {38 124} Meta_Control_l {38 125} Meta_Control_l {38 126} Meta_Control_l {38 127} Meta_Control_l {39 0} semicolon {39 1} colon {39 2} semicolon {39 3} colon {39 4} semicolon {39 5} colon {39 6} semicolon {39 7} colon {39 8} Meta_semicolon {39 9} Meta_colon {39 10} Meta_semicolon {39 11} Meta_colon {39 12} Meta_semicolon {39 13} Meta_colon {39 14} Meta_semicolon {39 15} Meta_colon {39 16} semicolon {39 17} colon {39 18} semicolon {39 19} colon {39 20} semicolon {39 21} colon {39 22} semicolon {39 23} colon {39 24} Meta_semicolon {39 25} Meta_colon {39 26} Meta_semicolon {39 27} Meta_colon {39 28} Meta_semicolon {39 29} Meta_colon {39 30} Meta_semicolon {39 31} Meta_colon {39 32} semicolon {39 33} colon {39 34} semicolon {39 35} colon {39 36} semicolon {39 37} colon {39 38} semicolon {39 39} colon {39 40} Meta_semicolon {39 41} Meta_colon {39 42} Meta_semicolon {39 43} Meta_colon {39 44} Meta_semicolon {39 45} Meta_colon {39 46} Meta_semicolon {39 47} Meta_colon {39 48} semicolon {39 49} colon {39 50} semicolon {39 51} colon {39 52} semicolon {39 53} colon {39 54} semicolon {39 55} colon {39 56} Meta_semicolon {39 57} Meta_colon {39 58} Meta_semicolon {39 59} Meta_colon {39 60} Meta_semicolon {39 61} Meta_colon {39 62} Meta_semicolon {39 63} Meta_colon {39 64} semicolon {39 65} colon {39 66} semicolon {39 67} colon {39 68} semicolon {39 69} colon {39 70} semicolon {39 71} colon {39 72} Meta_semicolon {39 73} Meta_colon {39 74} Meta_semicolon {39 75} Meta_colon {39 76} Meta_semicolon {39 77} Meta_colon {39 78} Meta_semicolon {39 79} Meta_colon {39 80} semicolon {39 81} colon {39 82} semicolon {39 83} colon {39 84} semicolon {39 85} colon {39 86} semicolon {39 87} colon {39 88} Meta_semicolon {39 89} Meta_colon {39 90} Meta_semicolon {39 91} Meta_colon {39 92} Meta_semicolon {39 93} Meta_colon {39 94} Meta_semicolon {39 95} Meta_colon {39 96} semicolon {39 97} colon {39 98} semicolon {39 99} colon {39 100} semicolon {39 101} colon {39 102} semicolon {39 103} colon {39 104} Meta_semicolon {39 105} Meta_colon {39 106} Meta_semicolon {39 107} Meta_colon {39 108} Meta_semicolon {39 109} Meta_colon {39 110} Meta_semicolon {39 111} Meta_colon {39 112} semicolon {39 113} colon {39 114} semicolon {39 115} colon {39 116} semicolon {39 117} colon {39 118} semicolon {39 119} colon {39 120} Meta_semicolon {39 121} Meta_colon {39 122} Meta_semicolon {39 123} Meta_colon {39 124} Meta_semicolon {39 125} Meta_colon {39 126} Meta_semicolon {39 127} Meta_colon {40 0} apostrophe {40 1} quotedbl {40 2} apostrophe {40 3} quotedbl {40 4} apostrophe {40 5} quotedbl {40 6} apostrophe {40 7} quotedbl {40 8} Meta_apostrophe {40 9} Meta_quotedbl {40 10} Meta_apostrophe {40 11} Meta_quotedbl {40 12} Meta_apostrophe {40 13} Meta_quotedbl {40 14} Meta_apostrophe {40 15} Meta_quotedbl {40 16} apostrophe {40 17} quotedbl {40 18} apostrophe {40 19} quotedbl {40 20} apostrophe {40 21} quotedbl {40 22} apostrophe {40 23} quotedbl {40 24} Meta_apostrophe {40 25} Meta_quotedbl {40 26} Meta_apostrophe {40 27} Meta_quotedbl {40 28} Meta_apostrophe {40 29} Meta_quotedbl {40 30} Meta_apostrophe {40 31} Meta_quotedbl {40 32} apostrophe {40 33} quotedbl {40 34} apostrophe {40 35} quotedbl {40 36} apostrophe {40 37} quotedbl {40 38} apostrophe {40 39} quotedbl {40 40} Meta_apostrophe {40 41} Meta_quotedbl {40 42} Meta_apostrophe {40 43} Meta_quotedbl {40 44} Meta_apostrophe {40 45} Meta_quotedbl {40 46} Meta_apostrophe {40 47} Meta_quotedbl {40 48} apostrophe {40 49} quotedbl {40 50} apostrophe {40 51} quotedbl {40 52} apostrophe {40 53} quotedbl {40 54} apostrophe {40 55} quotedbl {40 56} Meta_apostrophe {40 57} Meta_quotedbl {40 58} Meta_apostrophe {40 59} Meta_quotedbl {40 60} Meta_apostrophe {40 61} Meta_quotedbl {40 62} Meta_apostrophe {40 63} Meta_quotedbl {40 64} apostrophe {40 65} quotedbl {40 66} apostrophe {40 67} quotedbl {40 68} apostrophe {40 69} quotedbl {40 70} apostrophe {40 71} quotedbl {40 72} Meta_apostrophe {40 73} Meta_quotedbl {40 74} Meta_apostrophe {40 75} Meta_quotedbl {40 76} Meta_apostrophe {40 77} Meta_quotedbl {40 78} Meta_apostrophe {40 79} Meta_quotedbl {40 80} apostrophe {40 81} quotedbl {40 82} apostrophe {40 83} quotedbl {40 84} apostrophe {40 85} quotedbl {40 86} apostrophe {40 87} quotedbl {40 88} Meta_apostrophe {40 89} Meta_quotedbl {40 90} Meta_apostrophe {40 91} Meta_quotedbl {40 92} Meta_apostrophe {40 93} Meta_quotedbl {40 94} Meta_apostrophe {40 95} Meta_quotedbl {40 96} apostrophe {40 97} quotedbl {40 98} apostrophe {40 99} quotedbl {40 100} apostrophe {40 101} quotedbl {40 102} apostrophe {40 103} quotedbl {40 104} Meta_apostrophe {40 105} Meta_quotedbl {40 106} Meta_apostrophe {40 107} Meta_quotedbl {40 108} Meta_apostrophe {40 109} Meta_quotedbl {40 110} Meta_apostrophe {40 111} Meta_quotedbl {40 112} apostrophe {40 113} quotedbl {40 114} apostrophe {40 115} quotedbl {40 116} apostrophe {40 117} quotedbl {40 118} apostrophe {40 119} quotedbl {40 120} Meta_apostrophe {40 121} Meta_quotedbl {40 122} Meta_apostrophe {40 123} Meta_quotedbl {40 124} Meta_apostrophe {40 125} Meta_quotedbl {40 126} Meta_apostrophe {40 127} Meta_quotedbl {41 0} grave {41 1} asciitilde {41 2} grave {41 3} asciitilde {41 4} nul {41 5} Control_asciicircum {41 6} nul {41 7} Control_asciicircum {41 8} Meta_grave {41 9} Meta_asciitilde {41 10} Meta_grave {41 11} Meta_asciitilde {41 12} Meta_nul {41 13} Meta_Control_asciicircum {41 14} Meta_nul {41 15} Meta_Control_asciicircum {41 16} grave {41 17} asciitilde {41 18} grave {41 19} asciitilde {41 20} nul {41 21} Control_asciicircum {41 22} nul {41 23} Control_asciicircum {41 24} Meta_grave {41 25} Meta_asciitilde {41 26} Meta_grave {41 27} Meta_asciitilde {41 28} Meta_nul {41 29} Meta_Control_asciicircum {41 30} Meta_nul {41 31} Meta_Control_asciicircum {41 32} grave {41 33} asciitilde {41 34} grave {41 35} asciitilde {41 36} nul {41 37} Control_asciicircum {41 38} nul {41 39} Control_asciicircum {41 40} Meta_grave {41 41} Meta_asciitilde {41 42} Meta_grave {41 43} Meta_asciitilde {41 44} Meta_nul {41 45} Meta_Control_asciicircum {41 46} Meta_nul {41 47} Meta_Control_asciicircum {41 48} grave {41 49} asciitilde {41 50} grave {41 51} asciitilde {41 52} nul {41 53} Control_asciicircum {41 54} nul {41 55} Control_asciicircum {41 56} Meta_grave {41 57} Meta_asciitilde {41 58} Meta_grave {41 59} Meta_asciitilde {41 60} Meta_nul {41 61} Meta_Control_asciicircum {41 62} Meta_nul {41 63} Meta_Control_asciicircum {41 64} grave {41 65} asciitilde {41 66} grave {41 67} asciitilde {41 68} nul {41 69} Control_asciicircum {41 70} nul {41 71} Control_asciicircum {41 72} Meta_grave {41 73} Meta_asciitilde {41 74} Meta_grave {41 75} Meta_asciitilde {41 76} Meta_nul {41 77} Meta_Control_asciicircum {41 78} Meta_nul {41 79} Meta_Control_asciicircum {41 80} grave {41 81} asciitilde {41 82} grave {41 83} asciitilde {41 84} nul {41 85} Control_asciicircum {41 86} nul {41 87} Control_asciicircum {41 88} Meta_grave {41 89} Meta_asciitilde {41 90} Meta_grave {41 91} Meta_asciitilde {41 92} Meta_nul {41 93} Meta_Control_asciicircum {41 94} Meta_nul {41 95} Meta_Control_asciicircum {41 96} grave {41 97} asciitilde {41 98} grave {41 99} asciitilde {41 100} nul {41 101} Control_asciicircum {41 102} nul {41 103} Control_asciicircum {41 104} Meta_grave {41 105} Meta_asciitilde {41 106} Meta_grave {41 107} Meta_asciitilde {41 108} Meta_nul {41 109} Meta_Control_asciicircum {41 110} Meta_nul {41 111} Meta_Control_asciicircum {41 112} grave {41 113} asciitilde {41 114} grave {41 115} asciitilde {41 116} nul {41 117} Control_asciicircum {41 118} nul {41 119} Control_asciicircum {41 120} Meta_grave {41 121} Meta_asciitilde {41 122} Meta_grave {41 123} Meta_asciitilde {41 124} Meta_nul {41 125} Meta_Control_asciicircum {41 126} Meta_nul {41 127} Meta_Control_asciicircum {42 0} Shift {42 1} Shift {42 2} Shift {42 3} Shift {42 4} Shift {42 5} Shift {42 6} Shift {42 7} Shift {42 8} Shift {42 9} Shift {42 10} Shift {42 11} Shift {42 12} Shift {42 13} Shift {42 14} Shift {42 15} Shift {42 16} Shift {42 17} Shift {42 18} Shift {42 19} Shift {42 20} Shift {42 21} Shift {42 22} Shift {42 23} Shift {42 24} Shift {42 25} Shift {42 26} Shift {42 27} Shift {42 28} Shift {42 29} Shift {42 30} Shift {42 31} Shift {42 32} Shift {42 33} Shift {42 34} Shift {42 35} Shift {42 36} Shift {42 37} Shift {42 38} Shift {42 39} Shift {42 40} Shift {42 41} Shift {42 42} Shift {42 43} Shift {42 44} Shift {42 45} Shift {42 46} Shift {42 47} Shift {42 48} Shift {42 49} Shift {42 50} Shift {42 51} Shift {42 52} Shift {42 53} Shift {42 54} Shift {42 55} Shift {42 56} Shift {42 57} Shift {42 58} Shift {42 59} Shift {42 60} Shift {42 61} Shift {42 62} Shift {42 63} Shift {42 64} Shift {42 65} Shift {42 66} Shift {42 67} Shift {42 68} Shift {42 69} Shift {42 70} Shift {42 71} Shift {42 72} Shift {42 73} Shift {42 74} Shift {42 75} Shift {42 76} Shift {42 77} Shift {42 78} Shift {42 79} Shift {42 80} Shift {42 81} Shift {42 82} Shift {42 83} Shift {42 84} Shift {42 85} Shift {42 86} Shift {42 87} Shift {42 88} Shift {42 89} Shift {42 90} Shift {42 91} Shift {42 92} Shift {42 93} Shift {42 94} Shift {42 95} Shift {42 96} Shift {42 97} Shift {42 98} Shift {42 99} Shift {42 100} Shift {42 101} Shift {42 102} Shift {42 103} Shift {42 104} Shift {42 105} Shift {42 106} Shift {42 107} Shift {42 108} Shift {42 109} Shift {42 110} Shift {42 111} Shift {42 112} Shift {42 113} Shift {42 114} Shift {42 115} Shift {42 116} Shift {42 117} Shift {42 118} Shift {42 119} Shift {42 120} Shift {42 121} Shift {42 122} Shift {42 123} Shift {42 124} Shift {42 125} Shift {42 126} Shift {42 127} Shift {43 0} backslash {43 1} bar {43 2} backslash {43 3} bar {43 4} Control_backslash {43 5} Control_backslash {43 6} Control_backslash {43 7} Control_backslash {43 8} Meta_backslash {43 9} Meta_bar {43 10} Meta_backslash {43 11} Meta_bar {43 12} Meta_Control_backslash {43 13} Meta_Control_backslash {43 14} Meta_Control_backslash {43 15} Meta_Control_backslash {43 16} backslash {43 17} bar {43 18} backslash {43 19} bar {43 20} Control_backslash {43 21} Control_backslash {43 22} Control_backslash {43 23} Control_backslash {43 24} Meta_backslash {43 25} Meta_bar {43 26} Meta_backslash {43 27} Meta_bar {43 28} Meta_Control_backslash {43 29} Meta_Control_backslash {43 30} Meta_Control_backslash {43 31} Meta_Control_backslash {43 32} backslash {43 33} bar {43 34} backslash {43 35} bar {43 36} Control_backslash {43 37} Control_backslash {43 38} Control_backslash {43 39} Control_backslash {43 40} Meta_backslash {43 41} Meta_bar {43 42} Meta_backslash {43 43} Meta_bar {43 44} Meta_Control_backslash {43 45} Meta_Control_backslash {43 46} Meta_Control_backslash {43 47} Meta_Control_backslash {43 48} backslash {43 49} bar {43 50} backslash {43 51} bar {43 52} Control_backslash {43 53} Control_backslash {43 54} Control_backslash {43 55} Control_backslash {43 56} Meta_backslash {43 57} Meta_bar {43 58} Meta_backslash {43 59} Meta_bar {43 60} Meta_Control_backslash {43 61} Meta_Control_backslash {43 62} Meta_Control_backslash {43 63} Meta_Control_backslash {43 64} backslash {43 65} bar {43 66} backslash {43 67} bar {43 68} Control_backslash {43 69} Control_backslash {43 70} Control_backslash {43 71} Control_backslash {43 72} Meta_backslash {43 73} Meta_bar {43 74} Meta_backslash {43 75} Meta_bar {43 76} Meta_Control_backslash {43 77} Meta_Control_backslash {43 78} Meta_Control_backslash {43 79} Meta_Control_backslash {43 80} backslash {43 81} bar {43 82} backslash {43 83} bar {43 84} Control_backslash {43 85} Control_backslash {43 86} Control_backslash {43 87} Control_backslash {43 88} Meta_backslash {43 89} Meta_bar {43 90} Meta_backslash {43 91} Meta_bar {43 92} Meta_Control_backslash {43 93} Meta_Control_backslash {43 94} Meta_Control_backslash {43 95} Meta_Control_backslash {43 96} backslash {43 97} bar {43 98} backslash {43 99} bar {43 100} Control_backslash {43 101} Control_backslash {43 102} Control_backslash {43 103} Control_backslash {43 104} Meta_backslash {43 105} Meta_bar {43 106} Meta_backslash {43 107} Meta_bar {43 108} Meta_Control_backslash {43 109} Meta_Control_backslash {43 110} Meta_Control_backslash {43 111} Meta_Control_backslash {43 112} backslash {43 113} bar {43 114} backslash {43 115} bar {43 116} Control_backslash {43 117} Control_backslash {43 118} Control_backslash {43 119} Control_backslash {43 120} Meta_backslash {43 121} Meta_bar {43 122} Meta_backslash {43 123} Meta_bar {43 124} Meta_Control_backslash {43 125} Meta_Control_backslash {43 126} Meta_Control_backslash {43 127} Meta_Control_backslash {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} Control_z {44 5} Control_z {44 6} Control_z {44 7} Control_z {44 8} Meta_z {44 9} Meta_Z {44 10} Meta_z {44 11} Meta_Z {44 12} Meta_Control_z {44 13} Meta_Control_z {44 14} Meta_Control_z {44 15} Meta_Control_z {44 16} z {44 17} Z {44 18} z {44 19} Z {44 20} Control_z {44 21} Control_z {44 22} Control_z {44 23} Control_z {44 24} Meta_z {44 25} Meta_Z {44 26} Meta_z {44 27} Meta_Z {44 28} Meta_Control_z {44 29} Meta_Control_z {44 30} Meta_Control_z {44 31} Meta_Control_z {44 32} z {44 33} Z {44 34} z {44 35} Z {44 36} Control_z {44 37} Control_z {44 38} Control_z {44 39} Control_z {44 40} Meta_z {44 41} Meta_Z {44 42} Meta_z {44 43} Meta_Z {44 44} Meta_Control_z {44 45} Meta_Control_z {44 46} Meta_Control_z {44 47} Meta_Control_z {44 48} z {44 49} Z {44 50} z {44 51} Z {44 52} Control_z {44 53} Control_z {44 54} Control_z {44 55} Control_z {44 56} Meta_z {44 57} Meta_Z {44 58} Meta_z {44 59} Meta_Z {44 60} Meta_Control_z {44 61} Meta_Control_z {44 62} Meta_Control_z {44 63} Meta_Control_z {44 64} Z {44 65} z {44 66} Z {44 67} z {44 68} Control_z {44 69} Control_z {44 70} Control_z {44 71} Control_z {44 72} Meta_z {44 73} Meta_Z {44 74} Meta_z {44 75} Meta_Z {44 76} Meta_Control_z {44 77} Meta_Control_z {44 78} Meta_Control_z {44 79} Meta_Control_z {44 80} Z {44 81} z {44 82} Z {44 83} z {44 84} Control_z {44 85} Control_z {44 86} Control_z {44 87} Control_z {44 88} Meta_z {44 89} Meta_Z {44 90} Meta_z {44 91} Meta_Z {44 92} Meta_Control_z {44 93} Meta_Control_z {44 94} Meta_Control_z {44 95} Meta_Control_z {44 96} Z {44 97} z {44 98} Z {44 99} z {44 100} Control_z {44 101} Control_z {44 102} Control_z {44 103} Control_z {44 104} Meta_z {44 105} Meta_Z {44 106} Meta_z {44 107} Meta_Z {44 108} Meta_Control_z {44 109} Meta_Control_z {44 110} Meta_Control_z {44 111} Meta_Control_z {44 112} Z {44 113} z {44 114} Z {44 115} z {44 116} Control_z {44 117} Control_z {44 118} Control_z {44 119} Control_z {44 120} Meta_z {44 121} Meta_Z {44 122} Meta_z {44 123} Meta_Z {44 124} Meta_Control_z {44 125} Meta_Control_z {44 126} Meta_Control_z {44 127} Meta_Control_z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} Control_x {45 5} Control_x {45 6} Control_x {45 7} Control_x {45 8} Meta_x {45 9} Meta_X {45 10} Meta_x {45 11} Meta_X {45 12} Meta_Control_x {45 13} Meta_Control_x {45 14} Meta_Control_x {45 15} Meta_Control_x {45 16} x {45 17} X {45 18} x {45 19} X {45 20} Control_x {45 21} Control_x {45 22} Control_x {45 23} Control_x {45 24} Meta_x {45 25} Meta_X {45 26} Meta_x {45 27} Meta_X {45 28} Meta_Control_x {45 29} Meta_Control_x {45 30} Meta_Control_x {45 31} Meta_Control_x {45 32} x {45 33} X {45 34} x {45 35} X {45 36} Control_x {45 37} Control_x {45 38} Control_x {45 39} Control_x {45 40} Meta_x {45 41} Meta_X {45 42} Meta_x {45 43} Meta_X {45 44} Meta_Control_x {45 45} Meta_Control_x {45 46} Meta_Control_x {45 47} Meta_Control_x {45 48} x {45 49} X {45 50} x {45 51} X {45 52} Control_x {45 53} Control_x {45 54} Control_x {45 55} Control_x {45 56} Meta_x {45 57} Meta_X {45 58} Meta_x {45 59} Meta_X {45 60} Meta_Control_x {45 61} Meta_Control_x {45 62} Meta_Control_x {45 63} Meta_Control_x {45 64} X {45 65} x {45 66} X {45 67} x {45 68} Control_x {45 69} Control_x {45 70} Control_x {45 71} Control_x {45 72} Meta_x {45 73} Meta_X {45 74} Meta_x {45 75} Meta_X {45 76} Meta_Control_x {45 77} Meta_Control_x {45 78} Meta_Control_x {45 79} Meta_Control_x {45 80} X {45 81} x {45 82} X {45 83} x {45 84} Control_x {45 85} Control_x {45 86} Control_x {45 87} Control_x {45 88} Meta_x {45 89} Meta_X {45 90} Meta_x {45 91} Meta_X {45 92} Meta_Control_x {45 93} Meta_Control_x {45 94} Meta_Control_x {45 95} Meta_Control_x {45 96} X {45 97} x {45 98} X {45 99} x {45 100} Control_x {45 101} Control_x {45 102} Control_x {45 103} Control_x {45 104} Meta_x {45 105} Meta_X {45 106} Meta_x {45 107} Meta_X {45 108} Meta_Control_x {45 109} Meta_Control_x {45 110} Meta_Control_x {45 111} Meta_Control_x {45 112} X {45 113} x {45 114} X {45 115} x {45 116} Control_x {45 117} Control_x {45 118} Control_x {45 119} Control_x {45 120} Meta_x {45 121} Meta_X {45 122} Meta_x {45 123} Meta_X {45 124} Meta_Control_x {45 125} Meta_Control_x {45 126} Meta_Control_x {45 127} Meta_Control_x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} Control_c {46 5} Control_c {46 6} Control_c {46 7} Control_c {46 8} Meta_c {46 9} Meta_C {46 10} Meta_c {46 11} Meta_C {46 12} Meta_Control_c {46 13} Meta_Control_c {46 14} Meta_Control_c {46 15} Meta_Control_c {46 16} c {46 17} C {46 18} c {46 19} C {46 20} Control_c {46 21} Control_c {46 22} Control_c {46 23} Control_c {46 24} Meta_c {46 25} Meta_C {46 26} Meta_c {46 27} Meta_C {46 28} Meta_Control_c {46 29} Meta_Control_c {46 30} Meta_Control_c {46 31} Meta_Control_c {46 32} c {46 33} C {46 34} c {46 35} C {46 36} Control_c {46 37} Control_c {46 38} Control_c {46 39} Control_c {46 40} Meta_c {46 41} Meta_C {46 42} Meta_c {46 43} Meta_C {46 44} Meta_Control_c {46 45} Meta_Control_c {46 46} Meta_Control_c {46 47} Meta_Control_c {46 48} c {46 49} C {46 50} c {46 51} C {46 52} Control_c {46 53} Control_c {46 54} Control_c {46 55} Control_c {46 56} Meta_c {46 57} Meta_C {46 58} Meta_c {46 59} Meta_C {46 60} Meta_Control_c {46 61} Meta_Control_c {46 62} Meta_Control_c {46 63} Meta_Control_c {46 64} C {46 65} c {46 66} C {46 67} c {46 68} Control_c {46 69} Control_c {46 70} Control_c {46 71} Control_c {46 72} Meta_c {46 73} Meta_C {46 74} Meta_c {46 75} Meta_C {46 76} Meta_Control_c {46 77} Meta_Control_c {46 78} Meta_Control_c {46 79} Meta_Control_c {46 80} C {46 81} c {46 82} C {46 83} c {46 84} Control_c {46 85} Control_c {46 86} Control_c {46 87} Control_c {46 88} Meta_c {46 89} Meta_C {46 90} Meta_c {46 91} Meta_C {46 92} Meta_Control_c {46 93} Meta_Control_c {46 94} Meta_Control_c {46 95} Meta_Control_c {46 96} C {46 97} c {46 98} C {46 99} c {46 100} Control_c {46 101} Control_c {46 102} Control_c {46 103} Control_c {46 104} Meta_c {46 105} Meta_C {46 106} Meta_c {46 107} Meta_C {46 108} Meta_Control_c {46 109} Meta_Control_c {46 110} Meta_Control_c {46 111} Meta_Control_c {46 112} C {46 113} c {46 114} C {46 115} c {46 116} Control_c {46 117} Control_c {46 118} Control_c {46 119} Control_c {46 120} Meta_c {46 121} Meta_C {46 122} Meta_c {46 123} Meta_C {46 124} Meta_Control_c {46 125} Meta_Control_c {46 126} Meta_Control_c {46 127} Meta_Control_c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} Control_v {47 5} Control_v {47 6} Control_v {47 7} Control_v {47 8} Meta_v {47 9} Meta_V {47 10} Meta_v {47 11} Meta_V {47 12} Meta_Control_v {47 13} Meta_Control_v {47 14} Meta_Control_v {47 15} Meta_Control_v {47 16} v {47 17} V {47 18} v {47 19} V {47 20} Control_v {47 21} Control_v {47 22} Control_v {47 23} Control_v {47 24} Meta_v {47 25} Meta_V {47 26} Meta_v {47 27} Meta_V {47 28} Meta_Control_v {47 29} Meta_Control_v {47 30} Meta_Control_v {47 31} Meta_Control_v {47 32} v {47 33} V {47 34} v {47 35} V {47 36} Control_v {47 37} Control_v {47 38} Control_v {47 39} Control_v {47 40} Meta_v {47 41} Meta_V {47 42} Meta_v {47 43} Meta_V {47 44} Meta_Control_v {47 45} Meta_Control_v {47 46} Meta_Control_v {47 47} Meta_Control_v {47 48} v {47 49} V {47 50} v {47 51} V {47 52} Control_v {47 53} Control_v {47 54} Control_v {47 55} Control_v {47 56} Meta_v {47 57} Meta_V {47 58} Meta_v {47 59} Meta_V {47 60} Meta_Control_v {47 61} Meta_Control_v {47 62} Meta_Control_v {47 63} Meta_Control_v {47 64} V {47 65} v {47 66} V {47 67} v {47 68} Control_v {47 69} Control_v {47 70} Control_v {47 71} Control_v {47 72} Meta_v {47 73} Meta_V {47 74} Meta_v {47 75} Meta_V {47 76} Meta_Control_v {47 77} Meta_Control_v {47 78} Meta_Control_v {47 79} Meta_Control_v {47 80} V {47 81} v {47 82} V {47 83} v {47 84} Control_v {47 85} Control_v {47 86} Control_v {47 87} Control_v {47 88} Meta_v {47 89} Meta_V {47 90} Meta_v {47 91} Meta_V {47 92} Meta_Control_v {47 93} Meta_Control_v {47 94} Meta_Control_v {47 95} Meta_Control_v {47 96} V {47 97} v {47 98} V {47 99} v {47 100} Control_v {47 101} Control_v {47 102} Control_v {47 103} Control_v {47 104} Meta_v {47 105} Meta_V {47 106} Meta_v {47 107} Meta_V {47 108} Meta_Control_v {47 109} Meta_Control_v {47 110} Meta_Control_v {47 111} Meta_Control_v {47 112} V {47 113} v {47 114} V {47 115} v {47 116} Control_v {47 117} Control_v {47 118} Control_v {47 119} Control_v {47 120} Meta_v {47 121} Meta_V {47 122} Meta_v {47 123} Meta_V {47 124} Meta_Control_v {47 125} Meta_Control_v {47 126} Meta_Control_v {47 127} Meta_Control_v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} Control_b {48 5} Control_b {48 6} Control_b {48 7} Control_b {48 8} Meta_b {48 9} Meta_B {48 10} Meta_b {48 11} Meta_B {48 12} Meta_Control_b {48 13} Meta_Control_b {48 14} Meta_Control_b {48 15} Meta_Control_b {48 16} b {48 17} B {48 18} b {48 19} B {48 20} Control_b {48 21} Control_b {48 22} Control_b {48 23} Control_b {48 24} Meta_b {48 25} Meta_B {48 26} Meta_b {48 27} Meta_B {48 28} Meta_Control_b {48 29} Meta_Control_b {48 30} Meta_Control_b {48 31} Meta_Control_b {48 32} b {48 33} B {48 34} b {48 35} B {48 36} Control_b {48 37} Control_b {48 38} Control_b {48 39} Control_b {48 40} Meta_b {48 41} Meta_B {48 42} Meta_b {48 43} Meta_B {48 44} Meta_Control_b {48 45} Meta_Control_b {48 46} Meta_Control_b {48 47} Meta_Control_b {48 48} b {48 49} B {48 50} b {48 51} B {48 52} Control_b {48 53} Control_b {48 54} Control_b {48 55} Control_b {48 56} Meta_b {48 57} Meta_B {48 58} Meta_b {48 59} Meta_B {48 60} Meta_Control_b {48 61} Meta_Control_b {48 62} Meta_Control_b {48 63} Meta_Control_b {48 64} B {48 65} b {48 66} B {48 67} b {48 68} Control_b {48 69} Control_b {48 70} Control_b {48 71} Control_b {48 72} Meta_b {48 73} Meta_B {48 74} Meta_b {48 75} Meta_B {48 76} Meta_Control_b {48 77} Meta_Control_b {48 78} Meta_Control_b {48 79} Meta_Control_b {48 80} B {48 81} b {48 82} B {48 83} b {48 84} Control_b {48 85} Control_b {48 86} Control_b {48 87} Control_b {48 88} Meta_b {48 89} Meta_B {48 90} Meta_b {48 91} Meta_B {48 92} Meta_Control_b {48 93} Meta_Control_b {48 94} Meta_Control_b {48 95} Meta_Control_b {48 96} B {48 97} b {48 98} B {48 99} b {48 100} Control_b {48 101} Control_b {48 102} Control_b {48 103} Control_b {48 104} Meta_b {48 105} Meta_B {48 106} Meta_b {48 107} Meta_B {48 108} Meta_Control_b {48 109} Meta_Control_b {48 110} Meta_Control_b {48 111} Meta_Control_b {48 112} B {48 113} b {48 114} B {48 115} b {48 116} Control_b {48 117} Control_b {48 118} Control_b {48 119} Control_b {48 120} Meta_b {48 121} Meta_B {48 122} Meta_b {48 123} Meta_B {48 124} Meta_Control_b {48 125} Meta_Control_b {48 126} Meta_Control_b {48 127} Meta_Control_b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} Control_n {49 5} Control_n {49 6} Control_n {49 7} Control_n {49 8} Meta_n {49 9} Meta_N {49 10} Meta_n {49 11} Meta_N {49 12} Meta_Control_n {49 13} Meta_Control_n {49 14} Meta_Control_n {49 15} Meta_Control_n {49 16} n {49 17} N {49 18} n {49 19} N {49 20} Control_n {49 21} Control_n {49 22} Control_n {49 23} Control_n {49 24} Meta_n {49 25} Meta_N {49 26} Meta_n {49 27} Meta_N {49 28} Meta_Control_n {49 29} Meta_Control_n {49 30} Meta_Control_n {49 31} Meta_Control_n {49 32} n {49 33} N {49 34} n {49 35} N {49 36} Control_n {49 37} Control_n {49 38} Control_n {49 39} Control_n {49 40} Meta_n {49 41} Meta_N {49 42} Meta_n {49 43} Meta_N {49 44} Meta_Control_n {49 45} Meta_Control_n {49 46} Meta_Control_n {49 47} Meta_Control_n {49 48} n {49 49} N {49 50} n {49 51} N {49 52} Control_n {49 53} Control_n {49 54} Control_n {49 55} Control_n {49 56} Meta_n {49 57} Meta_N {49 58} Meta_n {49 59} Meta_N {49 60} Meta_Control_n {49 61} Meta_Control_n {49 62} Meta_Control_n {49 63} Meta_Control_n {49 64} N {49 65} n {49 66} N {49 67} n {49 68} Control_n {49 69} Control_n {49 70} Control_n {49 71} Control_n {49 72} Meta_n {49 73} Meta_N {49 74} Meta_n {49 75} Meta_N {49 76} Meta_Control_n {49 77} Meta_Control_n {49 78} Meta_Control_n {49 79} Meta_Control_n {49 80} N {49 81} n {49 82} N {49 83} n {49 84} Control_n {49 85} Control_n {49 86} Control_n {49 87} Control_n {49 88} Meta_n {49 89} Meta_N {49 90} Meta_n {49 91} Meta_N {49 92} Meta_Control_n {49 93} Meta_Control_n {49 94} Meta_Control_n {49 95} Meta_Control_n {49 96} N {49 97} n {49 98} N {49 99} n {49 100} Control_n {49 101} Control_n {49 102} Control_n {49 103} Control_n {49 104} Meta_n {49 105} Meta_N {49 106} Meta_n {49 107} Meta_N {49 108} Meta_Control_n {49 109} Meta_Control_n {49 110} Meta_Control_n {49 111} Meta_Control_n {49 112} N {49 113} n {49 114} N {49 115} n {49 116} Control_n {49 117} Control_n {49 118} Control_n {49 119} Control_n {49 120} Meta_n {49 121} Meta_N {49 122} Meta_n {49 123} Meta_N {49 124} Meta_Control_n {49 125} Meta_Control_n {49 126} Meta_Control_n {49 127} Meta_Control_n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} Return {50 5} Return {50 6} Return {50 7} Return {50 8} Meta_m {50 9} Meta_M {50 10} Meta_m {50 11} Meta_M {50 12} Meta_Control_m {50 13} Meta_Control_m {50 14} Meta_Control_m {50 15} Meta_Control_m {50 16} m {50 17} M {50 18} m {50 19} M {50 20} Return {50 21} Return {50 22} Return {50 23} Return {50 24} Meta_m {50 25} Meta_M {50 26} Meta_m {50 27} Meta_M {50 28} Meta_Control_m {50 29} Meta_Control_m {50 30} Meta_Control_m {50 31} Meta_Control_m {50 32} m {50 33} M {50 34} m {50 35} M {50 36} Return {50 37} Return {50 38} Return {50 39} Return {50 40} Meta_m {50 41} Meta_M {50 42} Meta_m {50 43} Meta_M {50 44} Meta_Control_m {50 45} Meta_Control_m {50 46} Meta_Control_m {50 47} Meta_Control_m {50 48} m {50 49} M {50 50} m {50 51} M {50 52} Return {50 53} Return {50 54} Return {50 55} Return {50 56} Meta_m {50 57} Meta_M {50 58} Meta_m {50 59} Meta_M {50 60} Meta_Control_m {50 61} Meta_Control_m {50 62} Meta_Control_m {50 63} Meta_Control_m {50 64} M {50 65} m {50 66} M {50 67} m {50 68} Return {50 69} Return {50 70} Return {50 71} Return {50 72} Meta_m {50 73} Meta_M {50 74} Meta_m {50 75} Meta_M {50 76} Meta_Control_m {50 77} Meta_Control_m {50 78} Meta_Control_m {50 79} Meta_Control_m {50 80} M {50 81} m {50 82} M {50 83} m {50 84} Return {50 85} Return {50 86} Return {50 87} Return {50 88} Meta_m {50 89} Meta_M {50 90} Meta_m {50 91} Meta_M {50 92} Meta_Control_m {50 93} Meta_Control_m {50 94} Meta_Control_m {50 95} Meta_Control_m {50 96} M {50 97} m {50 98} M {50 99} m {50 100} Return {50 101} Return {50 102} Return {50 103} Return {50 104} Meta_m {50 105} Meta_M {50 106} Meta_m {50 107} Meta_M {50 108} Meta_Control_m {50 109} Meta_Control_m {50 110} Meta_Control_m {50 111} Meta_Control_m {50 112} M {50 113} m {50 114} M {50 115} m {50 116} Return {50 117} Return {50 118} Return {50 119} Return {50 120} Meta_m {50 121} Meta_M {50 122} Meta_m {50 123} Meta_M {50 124} Meta_Control_m {50 125} Meta_Control_m {50 126} Meta_Control_m {50 127} Meta_Control_m {51 0} comma {51 1} less {51 2} comma {51 3} less {51 4} comma {51 5} less {51 6} comma {51 7} less {51 8} Meta_comma {51 9} Meta_less {51 10} Meta_comma {51 11} Meta_less {51 12} Meta_comma {51 13} Meta_less {51 14} Meta_comma {51 15} Meta_less {51 16} comma {51 17} less {51 18} comma {51 19} less {51 20} comma {51 21} less {51 22} comma {51 23} less {51 24} Meta_comma {51 25} Meta_less {51 26} Meta_comma {51 27} Meta_less {51 28} Meta_comma {51 29} Meta_less {51 30} Meta_comma {51 31} Meta_less {51 32} comma {51 33} less {51 34} comma {51 35} less {51 36} comma {51 37} less {51 38} comma {51 39} less {51 40} Meta_comma {51 41} Meta_less {51 42} Meta_comma {51 43} Meta_less {51 44} Meta_comma {51 45} Meta_less {51 46} Meta_comma {51 47} Meta_less {51 48} comma {51 49} less {51 50} comma {51 51} less {51 52} comma {51 53} less {51 54} comma {51 55} less {51 56} Meta_comma {51 57} Meta_less {51 58} Meta_comma {51 59} Meta_less {51 60} Meta_comma {51 61} Meta_less {51 62} Meta_comma {51 63} Meta_less {51 64} comma {51 65} less {51 66} comma {51 67} less {51 68} comma {51 69} less {51 70} comma {51 71} less {51 72} Meta_comma {51 73} Meta_less {51 74} Meta_comma {51 75} Meta_less {51 76} Meta_comma {51 77} Meta_less {51 78} Meta_comma {51 79} Meta_less {51 80} comma {51 81} less {51 82} comma {51 83} less {51 84} comma {51 85} less {51 86} comma {51 87} less {51 88} Meta_comma {51 89} Meta_less {51 90} Meta_comma {51 91} Meta_less {51 92} Meta_comma {51 93} Meta_less {51 94} Meta_comma {51 95} Meta_less {51 96} comma {51 97} less {51 98} comma {51 99} less {51 100} comma {51 101} less {51 102} comma {51 103} less {51 104} Meta_comma {51 105} Meta_less {51 106} Meta_comma {51 107} Meta_less {51 108} Meta_comma {51 109} Meta_less {51 110} Meta_comma {51 111} Meta_less {51 112} comma {51 113} less {51 114} comma {51 115} less {51 116} comma {51 117} less {51 118} comma {51 119} less {51 120} Meta_comma {51 121} Meta_less {51 122} Meta_comma {51 123} Meta_less {51 124} Meta_comma {51 125} Meta_less {51 126} Meta_comma {51 127} Meta_less {52 0} period {52 1} greater {52 2} period {52 3} greater {52 4} Compose {52 5} Compose {52 6} Compose {52 7} Compose {52 8} Meta_period {52 9} Meta_greater {52 10} Meta_period {52 11} Meta_greater {52 12} Compose {52 13} Compose {52 14} Compose {52 15} Compose {52 16} period {52 17} greater {52 18} period {52 19} greater {52 20} Compose {52 21} Compose {52 22} Compose {52 23} Compose {52 24} Meta_period {52 25} Meta_greater {52 26} Meta_period {52 27} Meta_greater {52 28} Compose {52 29} Compose {52 30} Compose {52 31} Compose {52 32} period {52 33} greater {52 34} period {52 35} greater {52 36} Compose {52 37} Compose {52 38} Compose {52 39} Compose {52 40} Meta_period {52 41} Meta_greater {52 42} Meta_period {52 43} Meta_greater {52 44} Compose {52 45} Compose {52 46} Compose {52 47} Compose {52 48} period {52 49} greater {52 50} period {52 51} greater {52 52} Compose {52 53} Compose {52 54} Compose {52 55} Compose {52 56} Meta_period {52 57} Meta_greater {52 58} Meta_period {52 59} Meta_greater {52 60} Compose {52 61} Compose {52 62} Compose {52 63} Compose {52 64} period {52 65} greater {52 66} period {52 67} greater {52 68} Compose {52 69} Compose {52 70} Compose {52 71} Compose {52 72} Meta_period {52 73} Meta_greater {52 74} Meta_period {52 75} Meta_greater {52 76} Compose {52 77} Compose {52 78} Compose {52 79} Compose {52 80} period {52 81} greater {52 82} period {52 83} greater {52 84} Compose {52 85} Compose {52 86} Compose {52 87} Compose {52 88} Meta_period {52 89} Meta_greater {52 90} Meta_period {52 91} Meta_greater {52 92} Compose {52 93} Compose {52 94} Compose {52 95} Compose {52 96} period {52 97} greater {52 98} period {52 99} greater {52 100} Compose {52 101} Compose {52 102} Compose {52 103} Compose {52 104} Meta_period {52 105} Meta_greater {52 106} Meta_period {52 107} Meta_greater {52 108} Compose {52 109} Compose {52 110} Compose {52 111} Compose {52 112} period {52 113} greater {52 114} period {52 115} greater {52 116} Compose {52 117} Compose {52 118} Compose {52 119} Compose {52 120} Meta_period {52 121} Meta_greater {52 122} Meta_period {52 123} Meta_greater {52 124} Compose {52 125} Compose {52 126} Compose {52 127} Compose {53 0} slash {53 1} question {53 2} slash {53 3} question {53 4} Delete {53 5} Delete {53 6} Delete {53 7} Delete {53 8} Meta_slash {53 9} Meta_question {53 10} Meta_slash {53 11} Meta_question {53 12} Meta_Delete {53 13} Meta_Delete {53 14} Meta_Delete {53 15} Meta_Delete {53 16} slash {53 17} question {53 18} slash {53 19} question {53 20} Delete {53 21} Delete {53 22} Delete {53 23} Delete {53 24} Meta_slash {53 25} Meta_question {53 26} Meta_slash {53 27} Meta_question {53 28} Meta_Delete {53 29} Meta_Delete {53 30} Meta_Delete {53 31} Meta_Delete {53 32} slash {53 33} question {53 34} slash {53 35} question {53 36} Delete {53 37} Delete {53 38} Delete {53 39} Delete {53 40} Meta_slash {53 41} Meta_question {53 42} Meta_slash {53 43} Meta_question {53 44} Meta_Delete {53 45} Meta_Delete {53 46} Meta_Delete {53 47} Meta_Delete {53 48} slash {53 49} question {53 50} slash {53 51} question {53 52} Delete {53 53} Delete {53 54} Delete {53 55} Delete {53 56} Meta_slash {53 57} Meta_question {53 58} Meta_slash {53 59} Meta_question {53 60} Meta_Delete {53 61} Meta_Delete {53 62} Meta_Delete {53 63} Meta_Delete {53 64} slash {53 65} question {53 66} slash {53 67} question {53 68} Delete {53 69} Delete {53 70} Delete {53 71} Delete {53 72} Meta_slash {53 73} Meta_question {53 74} Meta_slash {53 75} Meta_question {53 76} Meta_Delete {53 77} Meta_Delete {53 78} Meta_Delete {53 79} Meta_Delete {53 80} slash {53 81} question {53 82} slash {53 83} question {53 84} Delete {53 85} Delete {53 86} Delete {53 87} Delete {53 88} Meta_slash {53 89} Meta_question {53 90} Meta_slash {53 91} Meta_question {53 92} Meta_Delete {53 93} Meta_Delete {53 94} Meta_Delete {53 95} Meta_Delete {53 96} slash {53 97} question {53 98} slash {53 99} question {53 100} Delete {53 101} Delete {53 102} Delete {53 103} Delete {53 104} Meta_slash {53 105} Meta_question {53 106} Meta_slash {53 107} Meta_question {53 108} Meta_Delete {53 109} Meta_Delete {53 110} Meta_Delete {53 111} Meta_Delete {53 112} slash {53 113} question {53 114} slash {53 115} question {53 116} Delete {53 117} Delete {53 118} Delete {53 119} Delete {53 120} Meta_slash {53 121} Meta_question {53 122} Meta_slash {53 123} Meta_question {53 124} Meta_Delete {53 125} Meta_Delete {53 126} Meta_Delete {53 127} Meta_Delete {54 0} Shift {54 1} Shift {54 2} Shift {54 3} Shift {54 4} Shift {54 5} Shift {54 6} Shift {54 7} Shift {54 8} Shift {54 9} Shift {54 10} Shift {54 11} Shift {54 12} Shift {54 13} Shift {54 14} Shift {54 15} Shift {54 16} Shift {54 17} Shift {54 18} Shift {54 19} Shift {54 20} Shift {54 21} Shift {54 22} Shift {54 23} Shift {54 24} Shift {54 25} Shift {54 26} Shift {54 27} Shift {54 28} Shift {54 29} Shift {54 30} Shift {54 31} Shift {54 32} Shift {54 33} Shift {54 34} Shift {54 35} Shift {54 36} Shift {54 37} Shift {54 38} Shift {54 39} Shift {54 40} Shift {54 41} Shift {54 42} Shift {54 43} Shift {54 44} Shift {54 45} Shift {54 46} Shift {54 47} Shift {54 48} Shift {54 49} Shift {54 50} Shift {54 51} Shift {54 52} Shift {54 53} Shift {54 54} Shift {54 55} Shift {54 56} Shift {54 57} Shift {54 58} Shift {54 59} Shift {54 60} Shift {54 61} Shift {54 62} Shift {54 63} Shift {54 64} Shift {54 65} Shift {54 66} Shift {54 67} Shift {54 68} Shift {54 69} Shift {54 70} Shift {54 71} Shift {54 72} Shift {54 73} Shift {54 74} Shift {54 75} Shift {54 76} Shift {54 77} Shift {54 78} Shift {54 79} Shift {54 80} Shift {54 81} Shift {54 82} Shift {54 83} Shift {54 84} Shift {54 85} Shift {54 86} Shift {54 87} Shift {54 88} Shift {54 89} Shift {54 90} Shift {54 91} Shift {54 92} Shift {54 93} Shift {54 94} Shift {54 95} Shift {54 96} Shift {54 97} Shift {54 98} Shift {54 99} Shift {54 100} Shift {54 101} Shift {54 102} Shift {54 103} Shift {54 104} Shift {54 105} Shift {54 106} Shift {54 107} Shift {54 108} Shift {54 109} Shift {54 110} Shift {54 111} Shift {54 112} Shift {54 113} Shift {54 114} Shift {54 115} Shift {54 116} Shift {54 117} Shift {54 118} Shift {54 119} Shift {54 120} Shift {54 121} Shift {54 122} Shift {54 123} Shift {54 124} Shift {54 125} Shift {54 126} Shift {54 127} Shift {55 0} KP_Multiply {55 1} KP_Multiply {55 2} Hex_C {55 3} KP_Multiply {55 4} KP_Multiply {55 5} KP_Multiply {55 6} KP_Multiply {55 7} KP_Multiply {55 8} KP_Multiply {55 9} Hex_C {55 10} KP_Multiply {55 11} KP_Multiply {55 12} KP_Multiply {55 13} KP_Multiply {55 14} KP_Multiply {55 15} KP_Multiply {55 16} KP_Multiply {55 17} KP_Multiply {55 18} Hex_C {55 19} KP_Multiply {55 20} KP_Multiply {55 21} KP_Multiply {55 22} KP_Multiply {55 23} KP_Multiply {55 24} KP_Multiply {55 25} Hex_C {55 26} KP_Multiply {55 27} KP_Multiply {55 28} KP_Multiply {55 29} KP_Multiply {55 30} KP_Multiply {55 31} KP_Multiply {55 32} KP_Multiply {55 33} KP_Multiply {55 34} Hex_C {55 35} KP_Multiply {55 36} KP_Multiply {55 37} KP_Multiply {55 38} KP_Multiply {55 39} KP_Multiply {55 40} KP_Multiply {55 41} Hex_C {55 42} KP_Multiply {55 43} KP_Multiply {55 44} KP_Multiply {55 45} KP_Multiply {55 46} KP_Multiply {55 47} KP_Multiply {55 48} KP_Multiply {55 49} KP_Multiply {55 50} Hex_C {55 51} KP_Multiply {55 52} KP_Multiply {55 53} KP_Multiply {55 54} KP_Multiply {55 55} KP_Multiply {55 56} KP_Multiply {55 57} Hex_C {55 58} KP_Multiply {55 59} KP_Multiply {55 60} KP_Multiply {55 61} KP_Multiply {55 62} KP_Multiply {55 63} KP_Multiply {55 64} KP_Multiply {55 65} KP_Multiply {55 66} Hex_C {55 67} KP_Multiply {55 68} KP_Multiply {55 69} KP_Multiply {55 70} KP_Multiply {55 71} KP_Multiply {55 72} KP_Multiply {55 73} Hex_C {55 74} KP_Multiply {55 75} KP_Multiply {55 76} KP_Multiply {55 77} KP_Multiply {55 78} KP_Multiply {55 79} KP_Multiply {55 80} KP_Multiply {55 81} KP_Multiply {55 82} Hex_C {55 83} KP_Multiply {55 84} KP_Multiply {55 85} KP_Multiply {55 86} KP_Multiply {55 87} KP_Multiply {55 88} KP_Multiply {55 89} Hex_C {55 90} KP_Multiply {55 91} KP_Multiply {55 92} KP_Multiply {55 93} KP_Multiply {55 94} KP_Multiply {55 95} KP_Multiply {55 96} KP_Multiply {55 97} KP_Multiply {55 98} Hex_C {55 99} KP_Multiply {55 100} KP_Multiply {55 101} KP_Multiply {55 102} KP_Multiply {55 103} KP_Multiply {55 104} KP_Multiply {55 105} Hex_C {55 106} KP_Multiply {55 107} KP_Multiply {55 108} KP_Multiply {55 109} KP_Multiply {55 110} KP_Multiply {55 111} KP_Multiply {55 112} KP_Multiply {55 113} KP_Multiply {55 114} Hex_C {55 115} KP_Multiply {55 116} KP_Multiply {55 117} KP_Multiply {55 118} KP_Multiply {55 119} KP_Multiply {55 120} KP_Multiply {55 121} Hex_C {55 122} KP_Multiply {55 123} KP_Multiply {55 124} KP_Multiply {55 125} KP_Multiply {55 126} KP_Multiply {55 127} KP_Multiply {56 0} Alt {56 1} Alt {56 2} Alt {56 3} Alt {56 4} Alt {56 5} Alt {56 6} Alt {56 7} Alt {56 8} Alt {56 9} Alt {56 10} Alt {56 11} Alt {56 12} Alt {56 13} Alt {56 14} Alt {56 15} Alt {56 16} Alt {56 17} Alt {56 18} Alt {56 19} Alt {56 20} Alt {56 21} Alt {56 22} Alt {56 23} Alt {56 24} Alt {56 25} Alt {56 26} Alt {56 27} Alt {56 28} Alt {56 29} Alt {56 30} Alt {56 31} Alt {56 32} Alt {56 33} Alt {56 34} Alt {56 35} Alt {56 36} Alt {56 37} Alt {56 38} Alt {56 39} Alt {56 40} Alt {56 41} Alt {56 42} Alt {56 43} Alt {56 44} Alt {56 45} Alt {56 46} Alt {56 47} Alt {56 48} Alt {56 49} Alt {56 50} Alt {56 51} Alt {56 52} Alt {56 53} Alt {56 54} Alt {56 55} Alt {56 56} Alt {56 57} Alt {56 58} Alt {56 59} Alt {56 60} Alt {56 61} Alt {56 62} Alt {56 63} Alt {56 64} Alt {56 65} Alt {56 66} Alt {56 67} Alt {56 68} Alt {56 69} Alt {56 70} Alt {56 71} Alt {56 72} Alt {56 73} Alt {56 74} Alt {56 75} Alt {56 76} Alt {56 77} Alt {56 78} Alt {56 79} Alt {56 80} Alt {56 81} Alt {56 82} Alt {56 83} Alt {56 84} Alt {56 85} Alt {56 86} Alt {56 87} Alt {56 88} Alt {56 89} Alt {56 90} Alt {56 91} Alt {56 92} Alt {56 93} Alt {56 94} Alt {56 95} Alt {56 96} Alt {56 97} Alt {56 98} Alt {56 99} Alt {56 100} Alt {56 101} Alt {56 102} Alt {56 103} Alt {56 104} Alt {56 105} Alt {56 106} Alt {56 107} Alt {56 108} Alt {56 109} Alt {56 110} Alt {56 111} Alt {56 112} Alt {56 113} Alt {56 114} Alt {56 115} Alt {56 116} Alt {56 117} Alt {56 118} Alt {56 119} Alt {56 120} Alt {56 121} Alt {56 122} Alt {56 123} Alt {56 124} Alt {56 125} Alt {56 126} Alt {56 127} Alt {57 0} space {57 1} space {57 2} space {57 3} space {57 4} nul {57 5} nul {57 6} nul {57 7} nul {57 8} Meta_space {57 9} Meta_space {57 10} Meta_space {57 11} Meta_space {57 12} Meta_nul {57 13} Meta_nul {57 14} Meta_nul {57 15} Meta_nul {57 16} space {57 17} space {57 18} space {57 19} space {57 20} nul {57 21} nul {57 22} nul {57 23} nul {57 24} Meta_space {57 25} Meta_space {57 26} Meta_space {57 27} Meta_space {57 28} Meta_nul {57 29} Meta_nul {57 30} Meta_nul {57 31} Meta_nul {57 32} space {57 33} space {57 34} space {57 35} space {57 36} nul {57 37} nul {57 38} nul {57 39} nul {57 40} Meta_space {57 41} Meta_space {57 42} Meta_space {57 43} Meta_space {57 44} Meta_nul {57 45} Meta_nul {57 46} Meta_nul {57 47} Meta_nul {57 48} space {57 49} space {57 50} space {57 51} space {57 52} nul {57 53} nul {57 54} nul {57 55} nul {57 56} Meta_space {57 57} Meta_space {57 58} Meta_space {57 59} Meta_space {57 60} Meta_nul {57 61} Meta_nul {57 62} Meta_nul {57 63} Meta_nul {57 64} space {57 65} space {57 66} space {57 67} space {57 68} nul {57 69} nul {57 70} nul {57 71} nul {57 72} Meta_space {57 73} Meta_space {57 74} Meta_space {57 75} Meta_space {57 76} Meta_nul {57 77} Meta_nul {57 78} Meta_nul {57 79} Meta_nul {57 80} space {57 81} space {57 82} space {57 83} space {57 84} nul {57 85} nul {57 86} nul {57 87} nul {57 88} Meta_space {57 89} Meta_space {57 90} Meta_space {57 91} Meta_space {57 92} Meta_nul {57 93} Meta_nul {57 94} Meta_nul {57 95} Meta_nul {57 96} space {57 97} space {57 98} space {57 99} space {57 100} nul {57 101} nul {57 102} nul {57 103} nul {57 104} Meta_space {57 105} Meta_space {57 106} Meta_space {57 107} Meta_space {57 108} Meta_nul {57 109} Meta_nul {57 110} Meta_nul {57 111} Meta_nul {57 112} space {57 113} space {57 114} space {57 115} space {57 116} nul {57 117} nul {57 118} nul {57 119} nul {57 120} Meta_space {57 121} Meta_space {57 122} Meta_space {57 123} Meta_space {57 124} Meta_nul {57 125} Meta_nul {57 126} Meta_nul {57 127} Meta_nul {58 0} Caps_Lock {58 1} Caps_Lock {58 2} Caps_Lock {58 3} Caps_Lock {58 4} Caps_Lock {58 5} Caps_Lock {58 6} Caps_Lock {58 7} Caps_Lock {58 8} Caps_Lock {58 9} Caps_Lock {58 10} Caps_Lock {58 11} Caps_Lock {58 12} Caps_Lock {58 13} Caps_Lock {58 14} Caps_Lock {58 15} Caps_Lock {58 16} Caps_Lock {58 17} Caps_Lock {58 18} Caps_Lock {58 19} Caps_Lock {58 20} Caps_Lock {58 21} Caps_Lock {58 22} Caps_Lock {58 23} Caps_Lock {58 24} Caps_Lock {58 25} Caps_Lock {58 26} Caps_Lock {58 27} Caps_Lock {58 28} Caps_Lock {58 29} Caps_Lock {58 30} Caps_Lock {58 31} Caps_Lock {58 32} Caps_Lock {58 33} Caps_Lock {58 34} Caps_Lock {58 35} Caps_Lock {58 36} Caps_Lock {58 37} Caps_Lock {58 38} Caps_Lock {58 39} Caps_Lock {58 40} Caps_Lock {58 41} Caps_Lock {58 42} Caps_Lock {58 43} Caps_Lock {58 44} Caps_Lock {58 45} Caps_Lock {58 46} Caps_Lock {58 47} Caps_Lock {58 48} Caps_Lock {58 49} Caps_Lock {58 50} Caps_Lock {58 51} Caps_Lock {58 52} Caps_Lock {58 53} Caps_Lock {58 54} Caps_Lock {58 55} Caps_Lock {58 56} Caps_Lock {58 57} Caps_Lock {58 58} Caps_Lock {58 59} Caps_Lock {58 60} Caps_Lock {58 61} Caps_Lock {58 62} Caps_Lock {58 63} Caps_Lock {58 64} Caps_Lock {58 65} Caps_Lock {58 66} Caps_Lock {58 67} Caps_Lock {58 68} Caps_Lock {58 69} Caps_Lock {58 70} Caps_Lock {58 71} Caps_Lock {58 72} Caps_Lock {58 73} Caps_Lock {58 74} Caps_Lock {58 75} Caps_Lock {58 76} Caps_Lock {58 77} Caps_Lock {58 78} Caps_Lock {58 79} Caps_Lock {58 80} Caps_Lock {58 81} Caps_Lock {58 82} Caps_Lock {58 83} Caps_Lock {58 84} Caps_Lock {58 85} Caps_Lock {58 86} Caps_Lock {58 87} Caps_Lock {58 88} Caps_Lock {58 89} Caps_Lock {58 90} Caps_Lock {58 91} Caps_Lock {58 92} Caps_Lock {58 93} Caps_Lock {58 94} Caps_Lock {58 95} Caps_Lock {58 96} Caps_Lock {58 97} Caps_Lock {58 98} Caps_Lock {58 99} Caps_Lock {58 100} Caps_Lock {58 101} Caps_Lock {58 102} Caps_Lock {58 103} Caps_Lock {58 104} Caps_Lock {58 105} Caps_Lock {58 106} Caps_Lock {58 107} Caps_Lock {58 108} Caps_Lock {58 109} Caps_Lock {58 110} Caps_Lock {58 111} Caps_Lock {58 112} Caps_Lock {58 113} Caps_Lock {58 114} Caps_Lock {58 115} Caps_Lock {58 116} Caps_Lock {58 117} Caps_Lock {58 118} Caps_Lock {58 119} Caps_Lock {58 120} Caps_Lock {58 121} Caps_Lock {58 122} Caps_Lock {58 123} Caps_Lock {58 124} Caps_Lock {58 125} Caps_Lock {58 126} Caps_Lock {58 127} Caps_Lock {59 0} F1 {59 1} F13 {59 2} Console_13 {59 3} Console_25 {59 4} F25 {59 5} F37 {59 6} Console_13 {59 7} Console_25 {59 8} Console_1 {59 9} Console_13 {59 10} F1 {59 11} F1 {59 12} Console_1 {59 13} Console_13 {59 14} F1 {59 15} F1 {59 16} F1 {59 17} F13 {59 18} Console_13 {59 19} Console_25 {59 20} F25 {59 21} F37 {59 22} Console_13 {59 23} Console_25 {59 24} Console_1 {59 25} Console_13 {59 26} F1 {59 27} F1 {59 28} Console_1 {59 29} Console_13 {59 30} F1 {59 31} F1 {59 32} F1 {59 33} F13 {59 34} Console_13 {59 35} Console_25 {59 36} F25 {59 37} F37 {59 38} Console_13 {59 39} Console_25 {59 40} Console_1 {59 41} Console_13 {59 42} F1 {59 43} F1 {59 44} Console_1 {59 45} Console_13 {59 46} F1 {59 47} F1 {59 48} F1 {59 49} F13 {59 50} Console_13 {59 51} Console_25 {59 52} F25 {59 53} F37 {59 54} Console_13 {59 55} Console_25 {59 56} Console_1 {59 57} Console_13 {59 58} F1 {59 59} F1 {59 60} Console_1 {59 61} Console_13 {59 62} F1 {59 63} F1 {59 64} F1 {59 65} F13 {59 66} Console_13 {59 67} Console_25 {59 68} F25 {59 69} F37 {59 70} Console_13 {59 71} Console_25 {59 72} Console_1 {59 73} Console_13 {59 74} F1 {59 75} F1 {59 76} Console_1 {59 77} Console_13 {59 78} F1 {59 79} F1 {59 80} F1 {59 81} F13 {59 82} Console_13 {59 83} Console_25 {59 84} F25 {59 85} F37 {59 86} Console_13 {59 87} Console_25 {59 88} Console_1 {59 89} Console_13 {59 90} F1 {59 91} F1 {59 92} Console_1 {59 93} Console_13 {59 94} F1 {59 95} F1 {59 96} F1 {59 97} F13 {59 98} Console_13 {59 99} Console_25 {59 100} F25 {59 101} F37 {59 102} Console_13 {59 103} Console_25 {59 104} Console_1 {59 105} Console_13 {59 106} F1 {59 107} F1 {59 108} Console_1 {59 109} Console_13 {59 110} F1 {59 111} F1 {59 112} F1 {59 113} F13 {59 114} Console_13 {59 115} Console_25 {59 116} F25 {59 117} F37 {59 118} Console_13 {59 119} Console_25 {59 120} Console_1 {59 121} Console_13 {59 122} F1 {59 123} F1 {59 124} Console_1 {59 125} Console_13 {59 126} F1 {59 127} F1 {60 0} F2 {60 1} F14 {60 2} Console_14 {60 3} Console_26 {60 4} F26 {60 5} F38 {60 6} Console_14 {60 7} Console_26 {60 8} Console_2 {60 9} Console_14 {60 10} F2 {60 11} F2 {60 12} Console_2 {60 13} Console_14 {60 14} F2 {60 15} F2 {60 16} F2 {60 17} F14 {60 18} Console_14 {60 19} Console_26 {60 20} F26 {60 21} F38 {60 22} Console_14 {60 23} Console_26 {60 24} Console_2 {60 25} Console_14 {60 26} F2 {60 27} F2 {60 28} Console_2 {60 29} Console_14 {60 30} F2 {60 31} F2 {60 32} F2 {60 33} F14 {60 34} Console_14 {60 35} Console_26 {60 36} F26 {60 37} F38 {60 38} Console_14 {60 39} Console_26 {60 40} Console_2 {60 41} Console_14 {60 42} F2 {60 43} F2 {60 44} Console_2 {60 45} Console_14 {60 46} F2 {60 47} F2 {60 48} F2 {60 49} F14 {60 50} Console_14 {60 51} Console_26 {60 52} F26 {60 53} F38 {60 54} Console_14 {60 55} Console_26 {60 56} Console_2 {60 57} Console_14 {60 58} F2 {60 59} F2 {60 60} Console_2 {60 61} Console_14 {60 62} F2 {60 63} F2 {60 64} F2 {60 65} F14 {60 66} Console_14 {60 67} Console_26 {60 68} F26 {60 69} F38 {60 70} Console_14 {60 71} Console_26 {60 72} Console_2 {60 73} Console_14 {60 74} F2 {60 75} F2 {60 76} Console_2 {60 77} Console_14 {60 78} F2 {60 79} F2 {60 80} F2 {60 81} F14 {60 82} Console_14 {60 83} Console_26 {60 84} F26 {60 85} F38 {60 86} Console_14 {60 87} Console_26 {60 88} Console_2 {60 89} Console_14 {60 90} F2 {60 91} F2 {60 92} Console_2 {60 93} Console_14 {60 94} F2 {60 95} F2 {60 96} F2 {60 97} F14 {60 98} Console_14 {60 99} Console_26 {60 100} F26 {60 101} F38 {60 102} Console_14 {60 103} Console_26 {60 104} Console_2 {60 105} Console_14 {60 106} F2 {60 107} F2 {60 108} Console_2 {60 109} Console_14 {60 110} F2 {60 111} F2 {60 112} F2 {60 113} F14 {60 114} Console_14 {60 115} Console_26 {60 116} F26 {60 117} F38 {60 118} Console_14 {60 119} Console_26 {60 120} Console_2 {60 121} Console_14 {60 122} F2 {60 123} F2 {60 124} Console_2 {60 125} Console_14 {60 126} F2 {60 127} F2 {61 0} F3 {61 1} F15 {61 2} Console_15 {61 3} Console_27 {61 4} F27 {61 5} F39 {61 6} Console_15 {61 7} Console_27 {61 8} Console_3 {61 9} Console_15 {61 10} F3 {61 11} F3 {61 12} Console_3 {61 13} Console_15 {61 14} F3 {61 15} F3 {61 16} F3 {61 17} F15 {61 18} Console_15 {61 19} Console_27 {61 20} F27 {61 21} F39 {61 22} Console_15 {61 23} Console_27 {61 24} Console_3 {61 25} Console_15 {61 26} F3 {61 27} F3 {61 28} Console_3 {61 29} Console_15 {61 30} F3 {61 31} F3 {61 32} F3 {61 33} F15 {61 34} Console_15 {61 35} Console_27 {61 36} F27 {61 37} F39 {61 38} Console_15 {61 39} Console_27 {61 40} Console_3 {61 41} Console_15 {61 42} F3 {61 43} F3 {61 44} Console_3 {61 45} Console_15 {61 46} F3 {61 47} F3 {61 48} F3 {61 49} F15 {61 50} Console_15 {61 51} Console_27 {61 52} F27 {61 53} F39 {61 54} Console_15 {61 55} Console_27 {61 56} Console_3 {61 57} Console_15 {61 58} F3 {61 59} F3 {61 60} Console_3 {61 61} Console_15 {61 62} F3 {61 63} F3 {61 64} F3 {61 65} F15 {61 66} Console_15 {61 67} Console_27 {61 68} F27 {61 69} F39 {61 70} Console_15 {61 71} Console_27 {61 72} Console_3 {61 73} Console_15 {61 74} F3 {61 75} F3 {61 76} Console_3 {61 77} Console_15 {61 78} F3 {61 79} F3 {61 80} F3 {61 81} F15 {61 82} Console_15 {61 83} Console_27 {61 84} F27 {61 85} F39 {61 86} Console_15 {61 87} Console_27 {61 88} Console_3 {61 89} Console_15 {61 90} F3 {61 91} F3 {61 92} Console_3 {61 93} Console_15 {61 94} F3 {61 95} F3 {61 96} F3 {61 97} F15 {61 98} Console_15 {61 99} Console_27 {61 100} F27 {61 101} F39 {61 102} Console_15 {61 103} Console_27 {61 104} Console_3 {61 105} Console_15 {61 106} F3 {61 107} F3 {61 108} Console_3 {61 109} Console_15 {61 110} F3 {61 111} F3 {61 112} F3 {61 113} F15 {61 114} Console_15 {61 115} Console_27 {61 116} F27 {61 117} F39 {61 118} Console_15 {61 119} Console_27 {61 120} Console_3 {61 121} Console_15 {61 122} F3 {61 123} F3 {61 124} Console_3 {61 125} Console_15 {61 126} F3 {61 127} F3 {62 0} F4 {62 1} F16 {62 2} Console_16 {62 3} Console_28 {62 4} F28 {62 5} F40 {62 6} Console_16 {62 7} Console_28 {62 8} Console_4 {62 9} Console_16 {62 10} F4 {62 11} F4 {62 12} Console_4 {62 13} Console_16 {62 14} F4 {62 15} F4 {62 16} F4 {62 17} F16 {62 18} Console_16 {62 19} Console_28 {62 20} F28 {62 21} F40 {62 22} Console_16 {62 23} Console_28 {62 24} Console_4 {62 25} Console_16 {62 26} F4 {62 27} F4 {62 28} Console_4 {62 29} Console_16 {62 30} F4 {62 31} F4 {62 32} F4 {62 33} F16 {62 34} Console_16 {62 35} Console_28 {62 36} F28 {62 37} F40 {62 38} Console_16 {62 39} Console_28 {62 40} Console_4 {62 41} Console_16 {62 42} F4 {62 43} F4 {62 44} Console_4 {62 45} Console_16 {62 46} F4 {62 47} F4 {62 48} F4 {62 49} F16 {62 50} Console_16 {62 51} Console_28 {62 52} F28 {62 53} F40 {62 54} Console_16 {62 55} Console_28 {62 56} Console_4 {62 57} Console_16 {62 58} F4 {62 59} F4 {62 60} Console_4 {62 61} Console_16 {62 62} F4 {62 63} F4 {62 64} F4 {62 65} F16 {62 66} Console_16 {62 67} Console_28 {62 68} F28 {62 69} F40 {62 70} Console_16 {62 71} Console_28 {62 72} Console_4 {62 73} Console_16 {62 74} F4 {62 75} F4 {62 76} Console_4 {62 77} Console_16 {62 78} F4 {62 79} F4 {62 80} F4 {62 81} F16 {62 82} Console_16 {62 83} Console_28 {62 84} F28 {62 85} F40 {62 86} Console_16 {62 87} Console_28 {62 88} Console_4 {62 89} Console_16 {62 90} F4 {62 91} F4 {62 92} Console_4 {62 93} Console_16 {62 94} F4 {62 95} F4 {62 96} F4 {62 97} F16 {62 98} Console_16 {62 99} Console_28 {62 100} F28 {62 101} F40 {62 102} Console_16 {62 103} Console_28 {62 104} Console_4 {62 105} Console_16 {62 106} F4 {62 107} F4 {62 108} Console_4 {62 109} Console_16 {62 110} F4 {62 111} F4 {62 112} F4 {62 113} F16 {62 114} Console_16 {62 115} Console_28 {62 116} F28 {62 117} F40 {62 118} Console_16 {62 119} Console_28 {62 120} Console_4 {62 121} Console_16 {62 122} F4 {62 123} F4 {62 124} Console_4 {62 125} Console_16 {62 126} F4 {62 127} F4 {63 0} F5 {63 1} F17 {63 2} Console_17 {63 3} Console_29 {63 4} F29 {63 5} F41 {63 6} Console_17 {63 7} Console_29 {63 8} Console_5 {63 9} Console_17 {63 10} F5 {63 11} F5 {63 12} Console_5 {63 13} Console_17 {63 14} F5 {63 15} F5 {63 16} F5 {63 17} F17 {63 18} Console_17 {63 19} Console_29 {63 20} F29 {63 21} F41 {63 22} Console_17 {63 23} Console_29 {63 24} Console_5 {63 25} Console_17 {63 26} F5 {63 27} F5 {63 28} Console_5 {63 29} Console_17 {63 30} F5 {63 31} F5 {63 32} F5 {63 33} F17 {63 34} Console_17 {63 35} Console_29 {63 36} F29 {63 37} F41 {63 38} Console_17 {63 39} Console_29 {63 40} Console_5 {63 41} Console_17 {63 42} F5 {63 43} F5 {63 44} Console_5 {63 45} Console_17 {63 46} F5 {63 47} F5 {63 48} F5 {63 49} F17 {63 50} Console_17 {63 51} Console_29 {63 52} F29 {63 53} F41 {63 54} Console_17 {63 55} Console_29 {63 56} Console_5 {63 57} Console_17 {63 58} F5 {63 59} F5 {63 60} Console_5 {63 61} Console_17 {63 62} F5 {63 63} F5 {63 64} F5 {63 65} F17 {63 66} Console_17 {63 67} Console_29 {63 68} F29 {63 69} F41 {63 70} Console_17 {63 71} Console_29 {63 72} Console_5 {63 73} Console_17 {63 74} F5 {63 75} F5 {63 76} Console_5 {63 77} Console_17 {63 78} F5 {63 79} F5 {63 80} F5 {63 81} F17 {63 82} Console_17 {63 83} Console_29 {63 84} F29 {63 85} F41 {63 86} Console_17 {63 87} Console_29 {63 88} Console_5 {63 89} Console_17 {63 90} F5 {63 91} F5 {63 92} Console_5 {63 93} Console_17 {63 94} F5 {63 95} F5 {63 96} F5 {63 97} F17 {63 98} Console_17 {63 99} Console_29 {63 100} F29 {63 101} F41 {63 102} Console_17 {63 103} Console_29 {63 104} Console_5 {63 105} Console_17 {63 106} F5 {63 107} F5 {63 108} Console_5 {63 109} Console_17 {63 110} F5 {63 111} F5 {63 112} F5 {63 113} F17 {63 114} Console_17 {63 115} Console_29 {63 116} F29 {63 117} F41 {63 118} Console_17 {63 119} Console_29 {63 120} Console_5 {63 121} Console_17 {63 122} F5 {63 123} F5 {63 124} Console_5 {63 125} Console_17 {63 126} F5 {63 127} F5 {64 0} F6 {64 1} F18 {64 2} Console_18 {64 3} Console_30 {64 4} F30 {64 5} F42 {64 6} Console_18 {64 7} Console_30 {64 8} Console_6 {64 9} Console_18 {64 10} F6 {64 11} F6 {64 12} Console_6 {64 13} Console_18 {64 14} F6 {64 15} F6 {64 16} F6 {64 17} F18 {64 18} Console_18 {64 19} Console_30 {64 20} F30 {64 21} F42 {64 22} Console_18 {64 23} Console_30 {64 24} Console_6 {64 25} Console_18 {64 26} F6 {64 27} F6 {64 28} Console_6 {64 29} Console_18 {64 30} F6 {64 31} F6 {64 32} F6 {64 33} F18 {64 34} Console_18 {64 35} Console_30 {64 36} F30 {64 37} F42 {64 38} Console_18 {64 39} Console_30 {64 40} Console_6 {64 41} Console_18 {64 42} F6 {64 43} F6 {64 44} Console_6 {64 45} Console_18 {64 46} F6 {64 47} F6 {64 48} F6 {64 49} F18 {64 50} Console_18 {64 51} Console_30 {64 52} F30 {64 53} F42 {64 54} Console_18 {64 55} Console_30 {64 56} Console_6 {64 57} Console_18 {64 58} F6 {64 59} F6 {64 60} Console_6 {64 61} Console_18 {64 62} F6 {64 63} F6 {64 64} F6 {64 65} F18 {64 66} Console_18 {64 67} Console_30 {64 68} F30 {64 69} F42 {64 70} Console_18 {64 71} Console_30 {64 72} Console_6 {64 73} Console_18 {64 74} F6 {64 75} F6 {64 76} Console_6 {64 77} Console_18 {64 78} F6 {64 79} F6 {64 80} F6 {64 81} F18 {64 82} Console_18 {64 83} Console_30 {64 84} F30 {64 85} F42 {64 86} Console_18 {64 87} Console_30 {64 88} Console_6 {64 89} Console_18 {64 90} F6 {64 91} F6 {64 92} Console_6 {64 93} Console_18 {64 94} F6 {64 95} F6 {64 96} F6 {64 97} F18 {64 98} Console_18 {64 99} Console_30 {64 100} F30 {64 101} F42 {64 102} Console_18 {64 103} Console_30 {64 104} Console_6 {64 105} Console_18 {64 106} F6 {64 107} F6 {64 108} Console_6 {64 109} Console_18 {64 110} F6 {64 111} F6 {64 112} F6 {64 113} F18 {64 114} Console_18 {64 115} Console_30 {64 116} F30 {64 117} F42 {64 118} Console_18 {64 119} Console_30 {64 120} Console_6 {64 121} Console_18 {64 122} F6 {64 123} F6 {64 124} Console_6 {64 125} Console_18 {64 126} F6 {64 127} F6 {65 0} F7 {65 1} F19 {65 2} Console_19 {65 3} Console_31 {65 4} F31 {65 5} F43 {65 6} Console_19 {65 7} Console_31 {65 8} Console_7 {65 9} Console_19 {65 10} F7 {65 11} F7 {65 12} Console_7 {65 13} Console_19 {65 14} F7 {65 15} F7 {65 16} F7 {65 17} F19 {65 18} Console_19 {65 19} Console_31 {65 20} F31 {65 21} F43 {65 22} Console_19 {65 23} Console_31 {65 24} Console_7 {65 25} Console_19 {65 26} F7 {65 27} F7 {65 28} Console_7 {65 29} Console_19 {65 30} F7 {65 31} F7 {65 32} F7 {65 33} F19 {65 34} Console_19 {65 35} Console_31 {65 36} F31 {65 37} F43 {65 38} Console_19 {65 39} Console_31 {65 40} Console_7 {65 41} Console_19 {65 42} F7 {65 43} F7 {65 44} Console_7 {65 45} Console_19 {65 46} F7 {65 47} F7 {65 48} F7 {65 49} F19 {65 50} Console_19 {65 51} Console_31 {65 52} F31 {65 53} F43 {65 54} Console_19 {65 55} Console_31 {65 56} Console_7 {65 57} Console_19 {65 58} F7 {65 59} F7 {65 60} Console_7 {65 61} Console_19 {65 62} F7 {65 63} F7 {65 64} F7 {65 65} F19 {65 66} Console_19 {65 67} Console_31 {65 68} F31 {65 69} F43 {65 70} Console_19 {65 71} Console_31 {65 72} Console_7 {65 73} Console_19 {65 74} F7 {65 75} F7 {65 76} Console_7 {65 77} Console_19 {65 78} F7 {65 79} F7 {65 80} F7 {65 81} F19 {65 82} Console_19 {65 83} Console_31 {65 84} F31 {65 85} F43 {65 86} Console_19 {65 87} Console_31 {65 88} Console_7 {65 89} Console_19 {65 90} F7 {65 91} F7 {65 92} Console_7 {65 93} Console_19 {65 94} F7 {65 95} F7 {65 96} F7 {65 97} F19 {65 98} Console_19 {65 99} Console_31 {65 100} F31 {65 101} F43 {65 102} Console_19 {65 103} Console_31 {65 104} Console_7 {65 105} Console_19 {65 106} F7 {65 107} F7 {65 108} Console_7 {65 109} Console_19 {65 110} F7 {65 111} F7 {65 112} F7 {65 113} F19 {65 114} Console_19 {65 115} Console_31 {65 116} F31 {65 117} F43 {65 118} Console_19 {65 119} Console_31 {65 120} Console_7 {65 121} Console_19 {65 122} F7 {65 123} F7 {65 124} Console_7 {65 125} Console_19 {65 126} F7 {65 127} F7 {66 0} F8 {66 1} F20 {66 2} Console_20 {66 3} Console_32 {66 4} F32 {66 5} F44 {66 6} Console_20 {66 7} Console_32 {66 8} Console_8 {66 9} Console_20 {66 10} F8 {66 11} F8 {66 12} Console_8 {66 13} Console_20 {66 14} F8 {66 15} F8 {66 16} F8 {66 17} F20 {66 18} Console_20 {66 19} Console_32 {66 20} F32 {66 21} F44 {66 22} Console_20 {66 23} Console_32 {66 24} Console_8 {66 25} Console_20 {66 26} F8 {66 27} F8 {66 28} Console_8 {66 29} Console_20 {66 30} F8 {66 31} F8 {66 32} F8 {66 33} F20 {66 34} Console_20 {66 35} Console_32 {66 36} F32 {66 37} F44 {66 38} Console_20 {66 39} Console_32 {66 40} Console_8 {66 41} Console_20 {66 42} F8 {66 43} F8 {66 44} Console_8 {66 45} Console_20 {66 46} F8 {66 47} F8 {66 48} F8 {66 49} F20 {66 50} Console_20 {66 51} Console_32 {66 52} F32 {66 53} F44 {66 54} Console_20 {66 55} Console_32 {66 56} Console_8 {66 57} Console_20 {66 58} F8 {66 59} F8 {66 60} Console_8 {66 61} Console_20 {66 62} F8 {66 63} F8 {66 64} F8 {66 65} F20 {66 66} Console_20 {66 67} Console_32 {66 68} F32 {66 69} F44 {66 70} Console_20 {66 71} Console_32 {66 72} Console_8 {66 73} Console_20 {66 74} F8 {66 75} F8 {66 76} Console_8 {66 77} Console_20 {66 78} F8 {66 79} F8 {66 80} F8 {66 81} F20 {66 82} Console_20 {66 83} Console_32 {66 84} F32 {66 85} F44 {66 86} Console_20 {66 87} Console_32 {66 88} Console_8 {66 89} Console_20 {66 90} F8 {66 91} F8 {66 92} Console_8 {66 93} Console_20 {66 94} F8 {66 95} F8 {66 96} F8 {66 97} F20 {66 98} Console_20 {66 99} Console_32 {66 100} F32 {66 101} F44 {66 102} Console_20 {66 103} Console_32 {66 104} Console_8 {66 105} Console_20 {66 106} F8 {66 107} F8 {66 108} Console_8 {66 109} Console_20 {66 110} F8 {66 111} F8 {66 112} F8 {66 113} F20 {66 114} Console_20 {66 115} Console_32 {66 116} F32 {66 117} F44 {66 118} Console_20 {66 119} Console_32 {66 120} Console_8 {66 121} Console_20 {66 122} F8 {66 123} F8 {66 124} Console_8 {66 125} Console_20 {66 126} F8 {66 127} F8 {67 0} F9 {67 1} F21 {67 2} Console_21 {67 3} Console_33 {67 4} F33 {67 5} F45 {67 6} Console_21 {67 7} Console_33 {67 8} Console_9 {67 9} Console_21 {67 10} F9 {67 11} F9 {67 12} Console_9 {67 13} Console_21 {67 14} F9 {67 15} F9 {67 16} F9 {67 17} F21 {67 18} Console_21 {67 19} Console_33 {67 20} F33 {67 21} F45 {67 22} Console_21 {67 23} Console_33 {67 24} Console_9 {67 25} Console_21 {67 26} F9 {67 27} F9 {67 28} Console_9 {67 29} Console_21 {67 30} F9 {67 31} F9 {67 32} F9 {67 33} F21 {67 34} Console_21 {67 35} Console_33 {67 36} F33 {67 37} F45 {67 38} Console_21 {67 39} Console_33 {67 40} Console_9 {67 41} Console_21 {67 42} F9 {67 43} F9 {67 44} Console_9 {67 45} Console_21 {67 46} F9 {67 47} F9 {67 48} F9 {67 49} F21 {67 50} Console_21 {67 51} Console_33 {67 52} F33 {67 53} F45 {67 54} Console_21 {67 55} Console_33 {67 56} Console_9 {67 57} Console_21 {67 58} F9 {67 59} F9 {67 60} Console_9 {67 61} Console_21 {67 62} F9 {67 63} F9 {67 64} F9 {67 65} F21 {67 66} Console_21 {67 67} Console_33 {67 68} F33 {67 69} F45 {67 70} Console_21 {67 71} Console_33 {67 72} Console_9 {67 73} Console_21 {67 74} F9 {67 75} F9 {67 76} Console_9 {67 77} Console_21 {67 78} F9 {67 79} F9 {67 80} F9 {67 81} F21 {67 82} Console_21 {67 83} Console_33 {67 84} F33 {67 85} F45 {67 86} Console_21 {67 87} Console_33 {67 88} Console_9 {67 89} Console_21 {67 90} F9 {67 91} F9 {67 92} Console_9 {67 93} Console_21 {67 94} F9 {67 95} F9 {67 96} F9 {67 97} F21 {67 98} Console_21 {67 99} Console_33 {67 100} F33 {67 101} F45 {67 102} Console_21 {67 103} Console_33 {67 104} Console_9 {67 105} Console_21 {67 106} F9 {67 107} F9 {67 108} Console_9 {67 109} Console_21 {67 110} F9 {67 111} F9 {67 112} F9 {67 113} F21 {67 114} Console_21 {67 115} Console_33 {67 116} F33 {67 117} F45 {67 118} Console_21 {67 119} Console_33 {67 120} Console_9 {67 121} Console_21 {67 122} F9 {67 123} F9 {67 124} Console_9 {67 125} Console_21 {67 126} F9 {67 127} F9 {68 0} F10 {68 1} F22 {68 2} Console_22 {68 3} Console_34 {68 4} F34 {68 5} F46 {68 6} Console_22 {68 7} Console_34 {68 8} Console_10 {68 9} Console_22 {68 10} F10 {68 11} F10 {68 12} Console_10 {68 13} Console_22 {68 14} F10 {68 15} F10 {68 16} F10 {68 17} F22 {68 18} Console_22 {68 19} Console_34 {68 20} F34 {68 21} F46 {68 22} Console_22 {68 23} Console_34 {68 24} Console_10 {68 25} Console_22 {68 26} F10 {68 27} F10 {68 28} Console_10 {68 29} Console_22 {68 30} F10 {68 31} F10 {68 32} F10 {68 33} F22 {68 34} Console_22 {68 35} Console_34 {68 36} F34 {68 37} F46 {68 38} Console_22 {68 39} Console_34 {68 40} Console_10 {68 41} Console_22 {68 42} F10 {68 43} F10 {68 44} Console_10 {68 45} Console_22 {68 46} F10 {68 47} F10 {68 48} F10 {68 49} F22 {68 50} Console_22 {68 51} Console_34 {68 52} F34 {68 53} F46 {68 54} Console_22 {68 55} Console_34 {68 56} Console_10 {68 57} Console_22 {68 58} F10 {68 59} F10 {68 60} Console_10 {68 61} Console_22 {68 62} F10 {68 63} F10 {68 64} F10 {68 65} F22 {68 66} Console_22 {68 67} Console_34 {68 68} F34 {68 69} F46 {68 70} Console_22 {68 71} Console_34 {68 72} Console_10 {68 73} Console_22 {68 74} F10 {68 75} F10 {68 76} Console_10 {68 77} Console_22 {68 78} F10 {68 79} F10 {68 80} F10 {68 81} F22 {68 82} Console_22 {68 83} Console_34 {68 84} F34 {68 85} F46 {68 86} Console_22 {68 87} Console_34 {68 88} Console_10 {68 89} Console_22 {68 90} F10 {68 91} F10 {68 92} Console_10 {68 93} Console_22 {68 94} F10 {68 95} F10 {68 96} F10 {68 97} F22 {68 98} Console_22 {68 99} Console_34 {68 100} F34 {68 101} F46 {68 102} Console_22 {68 103} Console_34 {68 104} Console_10 {68 105} Console_22 {68 106} F10 {68 107} F10 {68 108} Console_10 {68 109} Console_22 {68 110} F10 {68 111} F10 {68 112} F10 {68 113} F22 {68 114} Console_22 {68 115} Console_34 {68 116} F34 {68 117} F46 {68 118} Console_22 {68 119} Console_34 {68 120} Console_10 {68 121} Console_22 {68 122} F10 {68 123} F10 {68 124} Console_10 {68 125} Console_22 {68 126} F10 {68 127} F10 {69 0} Num_Lock {69 1} Num_Lock {69 2} Hex_A {69 3} Num_Lock {69 4} Num_Lock {69 5} Num_Lock {69 6} Num_Lock {69 7} Num_Lock {69 8} Num_Lock {69 9} Hex_A {69 10} Num_Lock {69 11} Num_Lock {69 12} Num_Lock {69 13} Num_Lock {69 14} Num_Lock {69 15} Num_Lock {69 16} Num_Lock {69 17} Num_Lock {69 18} Hex_A {69 19} Num_Lock {69 20} Num_Lock {69 21} Num_Lock {69 22} Num_Lock {69 23} Num_Lock {69 24} Num_Lock {69 25} Hex_A {69 26} Num_Lock {69 27} Num_Lock {69 28} Num_Lock {69 29} Num_Lock {69 30} Num_Lock {69 31} Num_Lock {69 32} Num_Lock {69 33} Num_Lock {69 34} Hex_A {69 35} Num_Lock {69 36} Num_Lock {69 37} Num_Lock {69 38} Num_Lock {69 39} Num_Lock {69 40} Num_Lock {69 41} Hex_A {69 42} Num_Lock {69 43} Num_Lock {69 44} Num_Lock {69 45} Num_Lock {69 46} Num_Lock {69 47} Num_Lock {69 48} Num_Lock {69 49} Num_Lock {69 50} Hex_A {69 51} Num_Lock {69 52} Num_Lock {69 53} Num_Lock {69 54} Num_Lock {69 55} Num_Lock {69 56} Num_Lock {69 57} Hex_A {69 58} Num_Lock {69 59} Num_Lock {69 60} Num_Lock {69 61} Num_Lock {69 62} Num_Lock {69 63} Num_Lock {69 64} Num_Lock {69 65} Num_Lock {69 66} Hex_A {69 67} Num_Lock {69 68} Num_Lock {69 69} Num_Lock {69 70} Num_Lock {69 71} Num_Lock {69 72} Num_Lock {69 73} Hex_A {69 74} Num_Lock {69 75} Num_Lock {69 76} Num_Lock {69 77} Num_Lock {69 78} Num_Lock {69 79} Num_Lock {69 80} Num_Lock {69 81} Num_Lock {69 82} Hex_A {69 83} Num_Lock {69 84} Num_Lock {69 85} Num_Lock {69 86} Num_Lock {69 87} Num_Lock {69 88} Num_Lock {69 89} Hex_A {69 90} Num_Lock {69 91} Num_Lock {69 92} Num_Lock {69 93} Num_Lock {69 94} Num_Lock {69 95} Num_Lock {69 96} Num_Lock {69 97} Num_Lock {69 98} Hex_A {69 99} Num_Lock {69 100} Num_Lock {69 101} Num_Lock {69 102} Num_Lock {69 103} Num_Lock {69 104} Num_Lock {69 105} Hex_A {69 106} Num_Lock {69 107} Num_Lock {69 108} Num_Lock {69 109} Num_Lock {69 110} Num_Lock {69 111} Num_Lock {69 112} Num_Lock {69 113} Num_Lock {69 114} Hex_A {69 115} Num_Lock {69 116} Num_Lock {69 117} Num_Lock {69 118} Num_Lock {69 119} Num_Lock {69 120} Num_Lock {69 121} Hex_A {69 122} Num_Lock {69 123} Num_Lock {69 124} Num_Lock {69 125} Num_Lock {69 126} Num_Lock {69 127} Num_Lock {70 0} Scroll_Lock {70 1} Show_Memory {70 2} Show_Registers {70 3} Scroll_Lock {70 4} Show_State {70 5} Scroll_Lock {70 6} Scroll_Lock {70 7} Scroll_Lock {70 8} Show_Registers {70 9} Scroll_Lock {70 10} Scroll_Lock {70 11} Scroll_Lock {70 12} Scroll_Lock {70 13} Scroll_Lock {70 14} Scroll_Lock {70 15} Scroll_Lock {70 16} Scroll_Lock {70 17} Show_Memory {70 18} Show_Registers {70 19} Scroll_Lock {70 20} Show_State {70 21} Scroll_Lock {70 22} Scroll_Lock {70 23} Scroll_Lock {70 24} Show_Registers {70 25} Scroll_Lock {70 26} Scroll_Lock {70 27} Scroll_Lock {70 28} Scroll_Lock {70 29} Scroll_Lock {70 30} Scroll_Lock {70 31} Scroll_Lock {70 32} Scroll_Lock {70 33} Show_Memory {70 34} Show_Registers {70 35} Scroll_Lock {70 36} Show_State {70 37} Scroll_Lock {70 38} Scroll_Lock {70 39} Scroll_Lock {70 40} Show_Registers {70 41} Scroll_Lock {70 42} Scroll_Lock {70 43} Scroll_Lock {70 44} Scroll_Lock {70 45} Scroll_Lock {70 46} Scroll_Lock {70 47} Scroll_Lock {70 48} Scroll_Lock {70 49} Show_Memory {70 50} Show_Registers {70 51} Scroll_Lock {70 52} Show_State {70 53} Scroll_Lock {70 54} Scroll_Lock {70 55} Scroll_Lock {70 56} Show_Registers {70 57} Scroll_Lock {70 58} Scroll_Lock {70 59} Scroll_Lock {70 60} Scroll_Lock {70 61} Scroll_Lock {70 62} Scroll_Lock {70 63} Scroll_Lock {70 64} Scroll_Lock {70 65} Show_Memory {70 66} Show_Registers {70 67} Scroll_Lock {70 68} Show_State {70 69} Scroll_Lock {70 70} Scroll_Lock {70 71} Scroll_Lock {70 72} Show_Registers {70 73} Scroll_Lock {70 74} Scroll_Lock {70 75} Scroll_Lock {70 76} Scroll_Lock {70 77} Scroll_Lock {70 78} Scroll_Lock {70 79} Scroll_Lock {70 80} Scroll_Lock {70 81} Show_Memory {70 82} Show_Registers {70 83} Scroll_Lock {70 84} Show_State {70 85} Scroll_Lock {70 86} Scroll_Lock {70 87} Scroll_Lock {70 88} Show_Registers {70 89} Scroll_Lock {70 90} Scroll_Lock {70 91} Scroll_Lock {70 92} Scroll_Lock {70 93} Scroll_Lock {70 94} Scroll_Lock {70 95} Scroll_Lock {70 96} Scroll_Lock {70 97} Show_Memory {70 98} Show_Registers {70 99} Scroll_Lock {70 100} Show_State {70 101} Scroll_Lock {70 102} Scroll_Lock {70 103} Scroll_Lock {70 104} Show_Registers {70 105} Scroll_Lock {70 106} Scroll_Lock {70 107} Scroll_Lock {70 108} Scroll_Lock {70 109} Scroll_Lock {70 110} Scroll_Lock {70 111} Scroll_Lock {70 112} Scroll_Lock {70 113} Show_Memory {70 114} Show_Registers {70 115} Scroll_Lock {70 116} Show_State {70 117} Scroll_Lock {70 118} Scroll_Lock {70 119} Scroll_Lock {70 120} Show_Registers {70 121} Scroll_Lock {70 122} Scroll_Lock {70 123} Scroll_Lock {70 124} Scroll_Lock {70 125} Scroll_Lock {70 126} Scroll_Lock {70 127} Scroll_Lock {71 0} KP_7 {71 1} KP_7 {71 2} Hex_7 {71 3} KP_7 {71 4} KP_7 {71 5} KP_7 {71 6} KP_7 {71 7} KP_7 {71 8} Ascii_7 {71 9} Hex_7 {71 10} KP_7 {71 11} KP_7 {71 12} KP_7 {71 13} KP_7 {71 14} KP_7 {71 15} KP_7 {71 16} KP_7 {71 17} KP_7 {71 18} Hex_7 {71 19} KP_7 {71 20} KP_7 {71 21} KP_7 {71 22} KP_7 {71 23} KP_7 {71 24} Ascii_7 {71 25} Hex_7 {71 26} KP_7 {71 27} KP_7 {71 28} KP_7 {71 29} KP_7 {71 30} KP_7 {71 31} KP_7 {71 32} KP_7 {71 33} KP_7 {71 34} Hex_7 {71 35} KP_7 {71 36} KP_7 {71 37} KP_7 {71 38} KP_7 {71 39} KP_7 {71 40} Ascii_7 {71 41} Hex_7 {71 42} KP_7 {71 43} KP_7 {71 44} KP_7 {71 45} KP_7 {71 46} KP_7 {71 47} KP_7 {71 48} KP_7 {71 49} KP_7 {71 50} Hex_7 {71 51} KP_7 {71 52} KP_7 {71 53} KP_7 {71 54} KP_7 {71 55} KP_7 {71 56} Ascii_7 {71 57} Hex_7 {71 58} KP_7 {71 59} KP_7 {71 60} KP_7 {71 61} KP_7 {71 62} KP_7 {71 63} KP_7 {71 64} KP_7 {71 65} KP_7 {71 66} Hex_7 {71 67} KP_7 {71 68} KP_7 {71 69} KP_7 {71 70} KP_7 {71 71} KP_7 {71 72} Ascii_7 {71 73} Hex_7 {71 74} KP_7 {71 75} KP_7 {71 76} KP_7 {71 77} KP_7 {71 78} KP_7 {71 79} KP_7 {71 80} KP_7 {71 81} KP_7 {71 82} Hex_7 {71 83} KP_7 {71 84} KP_7 {71 85} KP_7 {71 86} KP_7 {71 87} KP_7 {71 88} Ascii_7 {71 89} Hex_7 {71 90} KP_7 {71 91} KP_7 {71 92} KP_7 {71 93} KP_7 {71 94} KP_7 {71 95} KP_7 {71 96} KP_7 {71 97} KP_7 {71 98} Hex_7 {71 99} KP_7 {71 100} KP_7 {71 101} KP_7 {71 102} KP_7 {71 103} KP_7 {71 104} Ascii_7 {71 105} Hex_7 {71 106} KP_7 {71 107} KP_7 {71 108} KP_7 {71 109} KP_7 {71 110} KP_7 {71 111} KP_7 {71 112} KP_7 {71 113} KP_7 {71 114} Hex_7 {71 115} KP_7 {71 116} KP_7 {71 117} KP_7 {71 118} KP_7 {71 119} KP_7 {71 120} Ascii_7 {71 121} Hex_7 {71 122} KP_7 {71 123} KP_7 {71 124} KP_7 {71 125} KP_7 {71 126} KP_7 {71 127} KP_7 {72 0} KP_8 {72 1} KP_8 {72 2} Hex_8 {72 3} KP_8 {72 4} KP_8 {72 5} KP_8 {72 6} KP_8 {72 7} KP_8 {72 8} Ascii_8 {72 9} Hex_8 {72 10} KP_8 {72 11} KP_8 {72 12} KP_8 {72 13} KP_8 {72 14} KP_8 {72 15} KP_8 {72 16} KP_8 {72 17} KP_8 {72 18} Hex_8 {72 19} KP_8 {72 20} KP_8 {72 21} KP_8 {72 22} KP_8 {72 23} KP_8 {72 24} Ascii_8 {72 25} Hex_8 {72 26} KP_8 {72 27} KP_8 {72 28} KP_8 {72 29} KP_8 {72 30} KP_8 {72 31} KP_8 {72 32} KP_8 {72 33} KP_8 {72 34} Hex_8 {72 35} KP_8 {72 36} KP_8 {72 37} KP_8 {72 38} KP_8 {72 39} KP_8 {72 40} Ascii_8 {72 41} Hex_8 {72 42} KP_8 {72 43} KP_8 {72 44} KP_8 {72 45} KP_8 {72 46} KP_8 {72 47} KP_8 {72 48} KP_8 {72 49} KP_8 {72 50} Hex_8 {72 51} KP_8 {72 52} KP_8 {72 53} KP_8 {72 54} KP_8 {72 55} KP_8 {72 56} Ascii_8 {72 57} Hex_8 {72 58} KP_8 {72 59} KP_8 {72 60} KP_8 {72 61} KP_8 {72 62} KP_8 {72 63} KP_8 {72 64} KP_8 {72 65} KP_8 {72 66} Hex_8 {72 67} KP_8 {72 68} KP_8 {72 69} KP_8 {72 70} KP_8 {72 71} KP_8 {72 72} Ascii_8 {72 73} Hex_8 {72 74} KP_8 {72 75} KP_8 {72 76} KP_8 {72 77} KP_8 {72 78} KP_8 {72 79} KP_8 {72 80} KP_8 {72 81} KP_8 {72 82} Hex_8 {72 83} KP_8 {72 84} KP_8 {72 85} KP_8 {72 86} KP_8 {72 87} KP_8 {72 88} Ascii_8 {72 89} Hex_8 {72 90} KP_8 {72 91} KP_8 {72 92} KP_8 {72 93} KP_8 {72 94} KP_8 {72 95} KP_8 {72 96} KP_8 {72 97} KP_8 {72 98} Hex_8 {72 99} KP_8 {72 100} KP_8 {72 101} KP_8 {72 102} KP_8 {72 103} KP_8 {72 104} Ascii_8 {72 105} Hex_8 {72 106} KP_8 {72 107} KP_8 {72 108} KP_8 {72 109} KP_8 {72 110} KP_8 {72 111} KP_8 {72 112} KP_8 {72 113} KP_8 {72 114} Hex_8 {72 115} KP_8 {72 116} KP_8 {72 117} KP_8 {72 118} KP_8 {72 119} KP_8 {72 120} Ascii_8 {72 121} Hex_8 {72 122} KP_8 {72 123} KP_8 {72 124} KP_8 {72 125} KP_8 {72 126} KP_8 {72 127} KP_8 {73 0} KP_9 {73 1} KP_9 {73 2} Hex_9 {73 3} KP_9 {73 4} KP_9 {73 5} KP_9 {73 6} KP_9 {73 7} KP_9 {73 8} Ascii_9 {73 9} Hex_9 {73 10} KP_9 {73 11} KP_9 {73 12} KP_9 {73 13} KP_9 {73 14} KP_9 {73 15} KP_9 {73 16} KP_9 {73 17} KP_9 {73 18} Hex_9 {73 19} KP_9 {73 20} KP_9 {73 21} KP_9 {73 22} KP_9 {73 23} KP_9 {73 24} Ascii_9 {73 25} Hex_9 {73 26} KP_9 {73 27} KP_9 {73 28} KP_9 {73 29} KP_9 {73 30} KP_9 {73 31} KP_9 {73 32} KP_9 {73 33} KP_9 {73 34} Hex_9 {73 35} KP_9 {73 36} KP_9 {73 37} KP_9 {73 38} KP_9 {73 39} KP_9 {73 40} Ascii_9 {73 41} Hex_9 {73 42} KP_9 {73 43} KP_9 {73 44} KP_9 {73 45} KP_9 {73 46} KP_9 {73 47} KP_9 {73 48} KP_9 {73 49} KP_9 {73 50} Hex_9 {73 51} KP_9 {73 52} KP_9 {73 53} KP_9 {73 54} KP_9 {73 55} KP_9 {73 56} Ascii_9 {73 57} Hex_9 {73 58} KP_9 {73 59} KP_9 {73 60} KP_9 {73 61} KP_9 {73 62} KP_9 {73 63} KP_9 {73 64} KP_9 {73 65} KP_9 {73 66} Hex_9 {73 67} KP_9 {73 68} KP_9 {73 69} KP_9 {73 70} KP_9 {73 71} KP_9 {73 72} Ascii_9 {73 73} Hex_9 {73 74} KP_9 {73 75} KP_9 {73 76} KP_9 {73 77} KP_9 {73 78} KP_9 {73 79} KP_9 {73 80} KP_9 {73 81} KP_9 {73 82} Hex_9 {73 83} KP_9 {73 84} KP_9 {73 85} KP_9 {73 86} KP_9 {73 87} KP_9 {73 88} Ascii_9 {73 89} Hex_9 {73 90} KP_9 {73 91} KP_9 {73 92} KP_9 {73 93} KP_9 {73 94} KP_9 {73 95} KP_9 {73 96} KP_9 {73 97} KP_9 {73 98} Hex_9 {73 99} KP_9 {73 100} KP_9 {73 101} KP_9 {73 102} KP_9 {73 103} KP_9 {73 104} Ascii_9 {73 105} Hex_9 {73 106} KP_9 {73 107} KP_9 {73 108} KP_9 {73 109} KP_9 {73 110} KP_9 {73 111} KP_9 {73 112} KP_9 {73 113} KP_9 {73 114} Hex_9 {73 115} KP_9 {73 116} KP_9 {73 117} KP_9 {73 118} KP_9 {73 119} KP_9 {73 120} Ascii_9 {73 121} Hex_9 {73 122} KP_9 {73 123} KP_9 {73 124} KP_9 {73 125} KP_9 {73 126} KP_9 {73 127} KP_9 {74 0} KP_Subtract {74 1} KP_Subtract {74 2} Hex_D {74 3} KP_Subtract {74 4} KP_Subtract {74 5} KP_Subtract {74 6} KP_Subtract {74 7} KP_Subtract {74 8} KP_Subtract {74 9} Hex_D {74 10} KP_Subtract {74 11} KP_Subtract {74 12} KP_Subtract {74 13} KP_Subtract {74 14} KP_Subtract {74 15} KP_Subtract {74 16} KP_Subtract {74 17} KP_Subtract {74 18} Hex_D {74 19} KP_Subtract {74 20} KP_Subtract {74 21} KP_Subtract {74 22} KP_Subtract {74 23} KP_Subtract {74 24} KP_Subtract {74 25} Hex_D {74 26} KP_Subtract {74 27} KP_Subtract {74 28} KP_Subtract {74 29} KP_Subtract {74 30} KP_Subtract {74 31} KP_Subtract {74 32} KP_Subtract {74 33} KP_Subtract {74 34} Hex_D {74 35} KP_Subtract {74 36} KP_Subtract {74 37} KP_Subtract {74 38} KP_Subtract {74 39} KP_Subtract {74 40} KP_Subtract {74 41} Hex_D {74 42} KP_Subtract {74 43} KP_Subtract {74 44} KP_Subtract {74 45} KP_Subtract {74 46} KP_Subtract {74 47} KP_Subtract {74 48} KP_Subtract {74 49} KP_Subtract {74 50} Hex_D {74 51} KP_Subtract {74 52} KP_Subtract {74 53} KP_Subtract {74 54} KP_Subtract {74 55} KP_Subtract {74 56} KP_Subtract {74 57} Hex_D {74 58} KP_Subtract {74 59} KP_Subtract {74 60} KP_Subtract {74 61} KP_Subtract {74 62} KP_Subtract {74 63} KP_Subtract {74 64} KP_Subtract {74 65} KP_Subtract {74 66} Hex_D {74 67} KP_Subtract {74 68} KP_Subtract {74 69} KP_Subtract {74 70} KP_Subtract {74 71} KP_Subtract {74 72} KP_Subtract {74 73} Hex_D {74 74} KP_Subtract {74 75} KP_Subtract {74 76} KP_Subtract {74 77} KP_Subtract {74 78} KP_Subtract {74 79} KP_Subtract {74 80} KP_Subtract {74 81} KP_Subtract {74 82} Hex_D {74 83} KP_Subtract {74 84} KP_Subtract {74 85} KP_Subtract {74 86} KP_Subtract {74 87} KP_Subtract {74 88} KP_Subtract {74 89} Hex_D {74 90} KP_Subtract {74 91} KP_Subtract {74 92} KP_Subtract {74 93} KP_Subtract {74 94} KP_Subtract {74 95} KP_Subtract {74 96} KP_Subtract {74 97} KP_Subtract {74 98} Hex_D {74 99} KP_Subtract {74 100} KP_Subtract {74 101} KP_Subtract {74 102} KP_Subtract {74 103} KP_Subtract {74 104} KP_Subtract {74 105} Hex_D {74 106} KP_Subtract {74 107} KP_Subtract {74 108} KP_Subtract {74 109} KP_Subtract {74 110} KP_Subtract {74 111} KP_Subtract {74 112} KP_Subtract {74 113} KP_Subtract {74 114} Hex_D {74 115} KP_Subtract {74 116} KP_Subtract {74 117} KP_Subtract {74 118} KP_Subtract {74 119} KP_Subtract {74 120} KP_Subtract {74 121} Hex_D {74 122} KP_Subtract {74 123} KP_Subtract {74 124} KP_Subtract {74 125} KP_Subtract {74 126} KP_Subtract {74 127} KP_Subtract {75 0} KP_4 {75 1} KP_4 {75 2} Hex_4 {75 3} KP_4 {75 4} KP_4 {75 5} KP_4 {75 6} KP_4 {75 7} KP_4 {75 8} Ascii_4 {75 9} Hex_4 {75 10} KP_4 {75 11} KP_4 {75 12} KP_4 {75 13} KP_4 {75 14} KP_4 {75 15} KP_4 {75 16} KP_4 {75 17} KP_4 {75 18} Hex_4 {75 19} KP_4 {75 20} KP_4 {75 21} KP_4 {75 22} KP_4 {75 23} KP_4 {75 24} Ascii_4 {75 25} Hex_4 {75 26} KP_4 {75 27} KP_4 {75 28} KP_4 {75 29} KP_4 {75 30} KP_4 {75 31} KP_4 {75 32} KP_4 {75 33} KP_4 {75 34} Hex_4 {75 35} KP_4 {75 36} KP_4 {75 37} KP_4 {75 38} KP_4 {75 39} KP_4 {75 40} Ascii_4 {75 41} Hex_4 {75 42} KP_4 {75 43} KP_4 {75 44} KP_4 {75 45} KP_4 {75 46} KP_4 {75 47} KP_4 {75 48} KP_4 {75 49} KP_4 {75 50} Hex_4 {75 51} KP_4 {75 52} KP_4 {75 53} KP_4 {75 54} KP_4 {75 55} KP_4 {75 56} Ascii_4 {75 57} Hex_4 {75 58} KP_4 {75 59} KP_4 {75 60} KP_4 {75 61} KP_4 {75 62} KP_4 {75 63} KP_4 {75 64} KP_4 {75 65} KP_4 {75 66} Hex_4 {75 67} KP_4 {75 68} KP_4 {75 69} KP_4 {75 70} KP_4 {75 71} KP_4 {75 72} Ascii_4 {75 73} Hex_4 {75 74} KP_4 {75 75} KP_4 {75 76} KP_4 {75 77} KP_4 {75 78} KP_4 {75 79} KP_4 {75 80} KP_4 {75 81} KP_4 {75 82} Hex_4 {75 83} KP_4 {75 84} KP_4 {75 85} KP_4 {75 86} KP_4 {75 87} KP_4 {75 88} Ascii_4 {75 89} Hex_4 {75 90} KP_4 {75 91} KP_4 {75 92} KP_4 {75 93} KP_4 {75 94} KP_4 {75 95} KP_4 {75 96} KP_4 {75 97} KP_4 {75 98} Hex_4 {75 99} KP_4 {75 100} KP_4 {75 101} KP_4 {75 102} KP_4 {75 103} KP_4 {75 104} Ascii_4 {75 105} Hex_4 {75 106} KP_4 {75 107} KP_4 {75 108} KP_4 {75 109} KP_4 {75 110} KP_4 {75 111} KP_4 {75 112} KP_4 {75 113} KP_4 {75 114} Hex_4 {75 115} KP_4 {75 116} KP_4 {75 117} KP_4 {75 118} KP_4 {75 119} KP_4 {75 120} Ascii_4 {75 121} Hex_4 {75 122} KP_4 {75 123} KP_4 {75 124} KP_4 {75 125} KP_4 {75 126} KP_4 {75 127} KP_4 {76 0} KP_5 {76 1} KP_5 {76 2} Hex_5 {76 3} KP_5 {76 4} KP_5 {76 5} KP_5 {76 6} KP_5 {76 7} KP_5 {76 8} Ascii_5 {76 9} Hex_5 {76 10} KP_5 {76 11} KP_5 {76 12} KP_5 {76 13} KP_5 {76 14} KP_5 {76 15} KP_5 {76 16} KP_5 {76 17} KP_5 {76 18} Hex_5 {76 19} KP_5 {76 20} KP_5 {76 21} KP_5 {76 22} KP_5 {76 23} KP_5 {76 24} Ascii_5 {76 25} Hex_5 {76 26} KP_5 {76 27} KP_5 {76 28} KP_5 {76 29} KP_5 {76 30} KP_5 {76 31} KP_5 {76 32} KP_5 {76 33} KP_5 {76 34} Hex_5 {76 35} KP_5 {76 36} KP_5 {76 37} KP_5 {76 38} KP_5 {76 39} KP_5 {76 40} Ascii_5 {76 41} Hex_5 {76 42} KP_5 {76 43} KP_5 {76 44} KP_5 {76 45} KP_5 {76 46} KP_5 {76 47} KP_5 {76 48} KP_5 {76 49} KP_5 {76 50} Hex_5 {76 51} KP_5 {76 52} KP_5 {76 53} KP_5 {76 54} KP_5 {76 55} KP_5 {76 56} Ascii_5 {76 57} Hex_5 {76 58} KP_5 {76 59} KP_5 {76 60} KP_5 {76 61} KP_5 {76 62} KP_5 {76 63} KP_5 {76 64} KP_5 {76 65} KP_5 {76 66} Hex_5 {76 67} KP_5 {76 68} KP_5 {76 69} KP_5 {76 70} KP_5 {76 71} KP_5 {76 72} Ascii_5 {76 73} Hex_5 {76 74} KP_5 {76 75} KP_5 {76 76} KP_5 {76 77} KP_5 {76 78} KP_5 {76 79} KP_5 {76 80} KP_5 {76 81} KP_5 {76 82} Hex_5 {76 83} KP_5 {76 84} KP_5 {76 85} KP_5 {76 86} KP_5 {76 87} KP_5 {76 88} Ascii_5 {76 89} Hex_5 {76 90} KP_5 {76 91} KP_5 {76 92} KP_5 {76 93} KP_5 {76 94} KP_5 {76 95} KP_5 {76 96} KP_5 {76 97} KP_5 {76 98} Hex_5 {76 99} KP_5 {76 100} KP_5 {76 101} KP_5 {76 102} KP_5 {76 103} KP_5 {76 104} Ascii_5 {76 105} Hex_5 {76 106} KP_5 {76 107} KP_5 {76 108} KP_5 {76 109} KP_5 {76 110} KP_5 {76 111} KP_5 {76 112} KP_5 {76 113} KP_5 {76 114} Hex_5 {76 115} KP_5 {76 116} KP_5 {76 117} KP_5 {76 118} KP_5 {76 119} KP_5 {76 120} Ascii_5 {76 121} Hex_5 {76 122} KP_5 {76 123} KP_5 {76 124} KP_5 {76 125} KP_5 {76 126} KP_5 {76 127} KP_5 {77 0} KP_6 {77 1} KP_6 {77 2} Hex_6 {77 3} KP_6 {77 4} KP_6 {77 5} KP_6 {77 6} KP_6 {77 7} KP_6 {77 8} Ascii_6 {77 9} Hex_6 {77 10} KP_6 {77 11} KP_6 {77 12} KP_6 {77 13} KP_6 {77 14} KP_6 {77 15} KP_6 {77 16} KP_6 {77 17} KP_6 {77 18} Hex_6 {77 19} KP_6 {77 20} KP_6 {77 21} KP_6 {77 22} KP_6 {77 23} KP_6 {77 24} Ascii_6 {77 25} Hex_6 {77 26} KP_6 {77 27} KP_6 {77 28} KP_6 {77 29} KP_6 {77 30} KP_6 {77 31} KP_6 {77 32} KP_6 {77 33} KP_6 {77 34} Hex_6 {77 35} KP_6 {77 36} KP_6 {77 37} KP_6 {77 38} KP_6 {77 39} KP_6 {77 40} Ascii_6 {77 41} Hex_6 {77 42} KP_6 {77 43} KP_6 {77 44} KP_6 {77 45} KP_6 {77 46} KP_6 {77 47} KP_6 {77 48} KP_6 {77 49} KP_6 {77 50} Hex_6 {77 51} KP_6 {77 52} KP_6 {77 53} KP_6 {77 54} KP_6 {77 55} KP_6 {77 56} Ascii_6 {77 57} Hex_6 {77 58} KP_6 {77 59} KP_6 {77 60} KP_6 {77 61} KP_6 {77 62} KP_6 {77 63} KP_6 {77 64} KP_6 {77 65} KP_6 {77 66} Hex_6 {77 67} KP_6 {77 68} KP_6 {77 69} KP_6 {77 70} KP_6 {77 71} KP_6 {77 72} Ascii_6 {77 73} Hex_6 {77 74} KP_6 {77 75} KP_6 {77 76} KP_6 {77 77} KP_6 {77 78} KP_6 {77 79} KP_6 {77 80} KP_6 {77 81} KP_6 {77 82} Hex_6 {77 83} KP_6 {77 84} KP_6 {77 85} KP_6 {77 86} KP_6 {77 87} KP_6 {77 88} Ascii_6 {77 89} Hex_6 {77 90} KP_6 {77 91} KP_6 {77 92} KP_6 {77 93} KP_6 {77 94} KP_6 {77 95} KP_6 {77 96} KP_6 {77 97} KP_6 {77 98} Hex_6 {77 99} KP_6 {77 100} KP_6 {77 101} KP_6 {77 102} KP_6 {77 103} KP_6 {77 104} Ascii_6 {77 105} Hex_6 {77 106} KP_6 {77 107} KP_6 {77 108} KP_6 {77 109} KP_6 {77 110} KP_6 {77 111} KP_6 {77 112} KP_6 {77 113} KP_6 {77 114} Hex_6 {77 115} KP_6 {77 116} KP_6 {77 117} KP_6 {77 118} KP_6 {77 119} KP_6 {77 120} Ascii_6 {77 121} Hex_6 {77 122} KP_6 {77 123} KP_6 {77 124} KP_6 {77 125} KP_6 {77 126} KP_6 {77 127} KP_6 {78 0} KP_Add {78 1} KP_Add {78 2} Hex_E {78 3} KP_Add {78 4} KP_Add {78 5} KP_Add {78 6} KP_Add {78 7} KP_Add {78 8} KP_Add {78 9} Hex_E {78 10} KP_Add {78 11} KP_Add {78 12} KP_Add {78 13} KP_Add {78 14} KP_Add {78 15} KP_Add {78 16} KP_Add {78 17} KP_Add {78 18} Hex_E {78 19} KP_Add {78 20} KP_Add {78 21} KP_Add {78 22} KP_Add {78 23} KP_Add {78 24} KP_Add {78 25} Hex_E {78 26} KP_Add {78 27} KP_Add {78 28} KP_Add {78 29} KP_Add {78 30} KP_Add {78 31} KP_Add {78 32} KP_Add {78 33} KP_Add {78 34} Hex_E {78 35} KP_Add {78 36} KP_Add {78 37} KP_Add {78 38} KP_Add {78 39} KP_Add {78 40} KP_Add {78 41} Hex_E {78 42} KP_Add {78 43} KP_Add {78 44} KP_Add {78 45} KP_Add {78 46} KP_Add {78 47} KP_Add {78 48} KP_Add {78 49} KP_Add {78 50} Hex_E {78 51} KP_Add {78 52} KP_Add {78 53} KP_Add {78 54} KP_Add {78 55} KP_Add {78 56} KP_Add {78 57} Hex_E {78 58} KP_Add {78 59} KP_Add {78 60} KP_Add {78 61} KP_Add {78 62} KP_Add {78 63} KP_Add {78 64} KP_Add {78 65} KP_Add {78 66} Hex_E {78 67} KP_Add {78 68} KP_Add {78 69} KP_Add {78 70} KP_Add {78 71} KP_Add {78 72} KP_Add {78 73} Hex_E {78 74} KP_Add {78 75} KP_Add {78 76} KP_Add {78 77} KP_Add {78 78} KP_Add {78 79} KP_Add {78 80} KP_Add {78 81} KP_Add {78 82} Hex_E {78 83} KP_Add {78 84} KP_Add {78 85} KP_Add {78 86} KP_Add {78 87} KP_Add {78 88} KP_Add {78 89} Hex_E {78 90} KP_Add {78 91} KP_Add {78 92} KP_Add {78 93} KP_Add {78 94} KP_Add {78 95} KP_Add {78 96} KP_Add {78 97} KP_Add {78 98} Hex_E {78 99} KP_Add {78 100} KP_Add {78 101} KP_Add {78 102} KP_Add {78 103} KP_Add {78 104} KP_Add {78 105} Hex_E {78 106} KP_Add {78 107} KP_Add {78 108} KP_Add {78 109} KP_Add {78 110} KP_Add {78 111} KP_Add {78 112} KP_Add {78 113} KP_Add {78 114} Hex_E {78 115} KP_Add {78 116} KP_Add {78 117} KP_Add {78 118} KP_Add {78 119} KP_Add {78 120} KP_Add {78 121} Hex_E {78 122} KP_Add {78 123} KP_Add {78 124} KP_Add {78 125} KP_Add {78 126} KP_Add {78 127} KP_Add {79 0} KP_1 {79 1} KP_1 {79 2} Hex_1 {79 3} KP_1 {79 4} KP_1 {79 5} KP_1 {79 6} KP_1 {79 7} KP_1 {79 8} Ascii_1 {79 9} Hex_1 {79 10} KP_1 {79 11} KP_1 {79 12} KP_1 {79 13} KP_1 {79 14} KP_1 {79 15} KP_1 {79 16} KP_1 {79 17} KP_1 {79 18} Hex_1 {79 19} KP_1 {79 20} KP_1 {79 21} KP_1 {79 22} KP_1 {79 23} KP_1 {79 24} Ascii_1 {79 25} Hex_1 {79 26} KP_1 {79 27} KP_1 {79 28} KP_1 {79 29} KP_1 {79 30} KP_1 {79 31} KP_1 {79 32} KP_1 {79 33} KP_1 {79 34} Hex_1 {79 35} KP_1 {79 36} KP_1 {79 37} KP_1 {79 38} KP_1 {79 39} KP_1 {79 40} Ascii_1 {79 41} Hex_1 {79 42} KP_1 {79 43} KP_1 {79 44} KP_1 {79 45} KP_1 {79 46} KP_1 {79 47} KP_1 {79 48} KP_1 {79 49} KP_1 {79 50} Hex_1 {79 51} KP_1 {79 52} KP_1 {79 53} KP_1 {79 54} KP_1 {79 55} KP_1 {79 56} Ascii_1 {79 57} Hex_1 {79 58} KP_1 {79 59} KP_1 {79 60} KP_1 {79 61} KP_1 {79 62} KP_1 {79 63} KP_1 {79 64} KP_1 {79 65} KP_1 {79 66} Hex_1 {79 67} KP_1 {79 68} KP_1 {79 69} KP_1 {79 70} KP_1 {79 71} KP_1 {79 72} Ascii_1 {79 73} Hex_1 {79 74} KP_1 {79 75} KP_1 {79 76} KP_1 {79 77} KP_1 {79 78} KP_1 {79 79} KP_1 {79 80} KP_1 {79 81} KP_1 {79 82} Hex_1 {79 83} KP_1 {79 84} KP_1 {79 85} KP_1 {79 86} KP_1 {79 87} KP_1 {79 88} Ascii_1 {79 89} Hex_1 {79 90} KP_1 {79 91} KP_1 {79 92} KP_1 {79 93} KP_1 {79 94} KP_1 {79 95} KP_1 {79 96} KP_1 {79 97} KP_1 {79 98} Hex_1 {79 99} KP_1 {79 100} KP_1 {79 101} KP_1 {79 102} KP_1 {79 103} KP_1 {79 104} Ascii_1 {79 105} Hex_1 {79 106} KP_1 {79 107} KP_1 {79 108} KP_1 {79 109} KP_1 {79 110} KP_1 {79 111} KP_1 {79 112} KP_1 {79 113} KP_1 {79 114} Hex_1 {79 115} KP_1 {79 116} KP_1 {79 117} KP_1 {79 118} KP_1 {79 119} KP_1 {79 120} Ascii_1 {79 121} Hex_1 {79 122} KP_1 {79 123} KP_1 {79 124} KP_1 {79 125} KP_1 {79 126} KP_1 {79 127} KP_1 {80 0} KP_2 {80 1} KP_2 {80 2} Hex_2 {80 3} KP_2 {80 4} KP_2 {80 5} KP_2 {80 6} KP_2 {80 7} KP_2 {80 8} Ascii_2 {80 9} Hex_2 {80 10} KP_2 {80 11} KP_2 {80 12} KP_2 {80 13} KP_2 {80 14} KP_2 {80 15} KP_2 {80 16} KP_2 {80 17} KP_2 {80 18} Hex_2 {80 19} KP_2 {80 20} KP_2 {80 21} KP_2 {80 22} KP_2 {80 23} KP_2 {80 24} Ascii_2 {80 25} Hex_2 {80 26} KP_2 {80 27} KP_2 {80 28} KP_2 {80 29} KP_2 {80 30} KP_2 {80 31} KP_2 {80 32} KP_2 {80 33} KP_2 {80 34} Hex_2 {80 35} KP_2 {80 36} KP_2 {80 37} KP_2 {80 38} KP_2 {80 39} KP_2 {80 40} Ascii_2 {80 41} Hex_2 {80 42} KP_2 {80 43} KP_2 {80 44} KP_2 {80 45} KP_2 {80 46} KP_2 {80 47} KP_2 {80 48} KP_2 {80 49} KP_2 {80 50} Hex_2 {80 51} KP_2 {80 52} KP_2 {80 53} KP_2 {80 54} KP_2 {80 55} KP_2 {80 56} Ascii_2 {80 57} Hex_2 {80 58} KP_2 {80 59} KP_2 {80 60} KP_2 {80 61} KP_2 {80 62} KP_2 {80 63} KP_2 {80 64} KP_2 {80 65} KP_2 {80 66} Hex_2 {80 67} KP_2 {80 68} KP_2 {80 69} KP_2 {80 70} KP_2 {80 71} KP_2 {80 72} Ascii_2 {80 73} Hex_2 {80 74} KP_2 {80 75} KP_2 {80 76} KP_2 {80 77} KP_2 {80 78} KP_2 {80 79} KP_2 {80 80} KP_2 {80 81} KP_2 {80 82} Hex_2 {80 83} KP_2 {80 84} KP_2 {80 85} KP_2 {80 86} KP_2 {80 87} KP_2 {80 88} Ascii_2 {80 89} Hex_2 {80 90} KP_2 {80 91} KP_2 {80 92} KP_2 {80 93} KP_2 {80 94} KP_2 {80 95} KP_2 {80 96} KP_2 {80 97} KP_2 {80 98} Hex_2 {80 99} KP_2 {80 100} KP_2 {80 101} KP_2 {80 102} KP_2 {80 103} KP_2 {80 104} Ascii_2 {80 105} Hex_2 {80 106} KP_2 {80 107} KP_2 {80 108} KP_2 {80 109} KP_2 {80 110} KP_2 {80 111} KP_2 {80 112} KP_2 {80 113} KP_2 {80 114} Hex_2 {80 115} KP_2 {80 116} KP_2 {80 117} KP_2 {80 118} KP_2 {80 119} KP_2 {80 120} Ascii_2 {80 121} Hex_2 {80 122} KP_2 {80 123} KP_2 {80 124} KP_2 {80 125} KP_2 {80 126} KP_2 {80 127} KP_2 {81 0} KP_3 {81 1} KP_3 {81 2} Hex_3 {81 3} KP_3 {81 4} KP_3 {81 5} KP_3 {81 6} KP_3 {81 7} KP_3 {81 8} Ascii_3 {81 9} Hex_3 {81 10} KP_3 {81 11} KP_3 {81 12} KP_3 {81 13} KP_3 {81 14} KP_3 {81 15} KP_3 {81 16} KP_3 {81 17} KP_3 {81 18} Hex_3 {81 19} KP_3 {81 20} KP_3 {81 21} KP_3 {81 22} KP_3 {81 23} KP_3 {81 24} Ascii_3 {81 25} Hex_3 {81 26} KP_3 {81 27} KP_3 {81 28} KP_3 {81 29} KP_3 {81 30} KP_3 {81 31} KP_3 {81 32} KP_3 {81 33} KP_3 {81 34} Hex_3 {81 35} KP_3 {81 36} KP_3 {81 37} KP_3 {81 38} KP_3 {81 39} KP_3 {81 40} Ascii_3 {81 41} Hex_3 {81 42} KP_3 {81 43} KP_3 {81 44} KP_3 {81 45} KP_3 {81 46} KP_3 {81 47} KP_3 {81 48} KP_3 {81 49} KP_3 {81 50} Hex_3 {81 51} KP_3 {81 52} KP_3 {81 53} KP_3 {81 54} KP_3 {81 55} KP_3 {81 56} Ascii_3 {81 57} Hex_3 {81 58} KP_3 {81 59} KP_3 {81 60} KP_3 {81 61} KP_3 {81 62} KP_3 {81 63} KP_3 {81 64} KP_3 {81 65} KP_3 {81 66} Hex_3 {81 67} KP_3 {81 68} KP_3 {81 69} KP_3 {81 70} KP_3 {81 71} KP_3 {81 72} Ascii_3 {81 73} Hex_3 {81 74} KP_3 {81 75} KP_3 {81 76} KP_3 {81 77} KP_3 {81 78} KP_3 {81 79} KP_3 {81 80} KP_3 {81 81} KP_3 {81 82} Hex_3 {81 83} KP_3 {81 84} KP_3 {81 85} KP_3 {81 86} KP_3 {81 87} KP_3 {81 88} Ascii_3 {81 89} Hex_3 {81 90} KP_3 {81 91} KP_3 {81 92} KP_3 {81 93} KP_3 {81 94} KP_3 {81 95} KP_3 {81 96} KP_3 {81 97} KP_3 {81 98} Hex_3 {81 99} KP_3 {81 100} KP_3 {81 101} KP_3 {81 102} KP_3 {81 103} KP_3 {81 104} Ascii_3 {81 105} Hex_3 {81 106} KP_3 {81 107} KP_3 {81 108} KP_3 {81 109} KP_3 {81 110} KP_3 {81 111} KP_3 {81 112} KP_3 {81 113} KP_3 {81 114} Hex_3 {81 115} KP_3 {81 116} KP_3 {81 117} KP_3 {81 118} KP_3 {81 119} KP_3 {81 120} Ascii_3 {81 121} Hex_3 {81 122} KP_3 {81 123} KP_3 {81 124} KP_3 {81 125} KP_3 {81 126} KP_3 {81 127} KP_3 {82 0} KP_0 {82 1} KP_0 {82 2} Hex_0 {82 3} KP_0 {82 4} KP_0 {82 5} KP_0 {82 6} KP_0 {82 7} KP_0 {82 8} Ascii_0 {82 9} Hex_0 {82 10} KP_0 {82 11} KP_0 {82 12} KP_0 {82 13} KP_0 {82 14} KP_0 {82 15} KP_0 {82 16} KP_0 {82 17} KP_0 {82 18} Hex_0 {82 19} KP_0 {82 20} KP_0 {82 21} KP_0 {82 22} KP_0 {82 23} KP_0 {82 24} Ascii_0 {82 25} Hex_0 {82 26} KP_0 {82 27} KP_0 {82 28} KP_0 {82 29} KP_0 {82 30} KP_0 {82 31} KP_0 {82 32} KP_0 {82 33} KP_0 {82 34} Hex_0 {82 35} KP_0 {82 36} KP_0 {82 37} KP_0 {82 38} KP_0 {82 39} KP_0 {82 40} Ascii_0 {82 41} Hex_0 {82 42} KP_0 {82 43} KP_0 {82 44} KP_0 {82 45} KP_0 {82 46} KP_0 {82 47} KP_0 {82 48} KP_0 {82 49} KP_0 {82 50} Hex_0 {82 51} KP_0 {82 52} KP_0 {82 53} KP_0 {82 54} KP_0 {82 55} KP_0 {82 56} Ascii_0 {82 57} Hex_0 {82 58} KP_0 {82 59} KP_0 {82 60} KP_0 {82 61} KP_0 {82 62} KP_0 {82 63} KP_0 {82 64} KP_0 {82 65} KP_0 {82 66} Hex_0 {82 67} KP_0 {82 68} KP_0 {82 69} KP_0 {82 70} KP_0 {82 71} KP_0 {82 72} Ascii_0 {82 73} Hex_0 {82 74} KP_0 {82 75} KP_0 {82 76} KP_0 {82 77} KP_0 {82 78} KP_0 {82 79} KP_0 {82 80} KP_0 {82 81} KP_0 {82 82} Hex_0 {82 83} KP_0 {82 84} KP_0 {82 85} KP_0 {82 86} KP_0 {82 87} KP_0 {82 88} Ascii_0 {82 89} Hex_0 {82 90} KP_0 {82 91} KP_0 {82 92} KP_0 {82 93} KP_0 {82 94} KP_0 {82 95} KP_0 {82 96} KP_0 {82 97} KP_0 {82 98} Hex_0 {82 99} KP_0 {82 100} KP_0 {82 101} KP_0 {82 102} KP_0 {82 103} KP_0 {82 104} Ascii_0 {82 105} Hex_0 {82 106} KP_0 {82 107} KP_0 {82 108} KP_0 {82 109} KP_0 {82 110} KP_0 {82 111} KP_0 {82 112} KP_0 {82 113} KP_0 {82 114} Hex_0 {82 115} KP_0 {82 116} KP_0 {82 117} KP_0 {82 118} KP_0 {82 119} KP_0 {82 120} Ascii_0 {82 121} Hex_0 {82 122} KP_0 {82 123} KP_0 {82 124} KP_0 {82 125} KP_0 {82 126} KP_0 {82 127} KP_0 {83 0} KP_Period {83 1} KP_Period {83 2} KP_Period {83 3} KP_Period {83 4} KP_Period {83 5} KP_Period {83 6} Boot {83 7} KP_Period {83 8} KP_Period {83 9} KP_Period {83 10} KP_Period {83 11} KP_Period {83 12} Boot {83 13} KP_Period {83 14} Boot {83 15} KP_Period {83 16} KP_Period {83 17} KP_Period {83 18} KP_Period {83 19} KP_Period {83 20} KP_Period {83 21} KP_Period {83 22} Boot {83 23} KP_Period {83 24} KP_Period {83 25} KP_Period {83 26} KP_Period {83 27} KP_Period {83 28} Boot {83 29} KP_Period {83 30} Boot {83 31} KP_Period {83 32} KP_Period {83 33} KP_Period {83 34} KP_Period {83 35} KP_Period {83 36} KP_Period {83 37} KP_Period {83 38} Boot {83 39} KP_Period {83 40} KP_Period {83 41} KP_Period {83 42} KP_Period {83 43} KP_Period {83 44} Boot {83 45} KP_Period {83 46} Boot {83 47} KP_Period {83 48} KP_Period {83 49} KP_Period {83 50} KP_Period {83 51} KP_Period {83 52} KP_Period {83 53} KP_Period {83 54} Boot {83 55} KP_Period {83 56} KP_Period {83 57} KP_Period {83 58} KP_Period {83 59} KP_Period {83 60} Boot {83 61} KP_Period {83 62} Boot {83 63} KP_Period {83 64} KP_Period {83 65} KP_Period {83 66} KP_Period {83 67} KP_Period {83 68} KP_Period {83 69} KP_Period {83 70} Boot {83 71} KP_Period {83 72} KP_Period {83 73} KP_Period {83 74} KP_Period {83 75} KP_Period {83 76} Boot {83 77} KP_Period {83 78} Boot {83 79} KP_Period {83 80} KP_Period {83 81} KP_Period {83 82} KP_Period {83 83} KP_Period {83 84} KP_Period {83 85} KP_Period {83 86} Boot {83 87} KP_Period {83 88} KP_Period {83 89} KP_Period {83 90} KP_Period {83 91} KP_Period {83 92} Boot {83 93} KP_Period {83 94} Boot {83 95} KP_Period {83 96} KP_Period {83 97} KP_Period {83 98} KP_Period {83 99} KP_Period {83 100} KP_Period {83 101} KP_Period {83 102} Boot {83 103} KP_Period {83 104} KP_Period {83 105} KP_Period {83 106} KP_Period {83 107} KP_Period {83 108} Boot {83 109} KP_Period {83 110} Boot {83 111} KP_Period {83 112} KP_Period {83 113} KP_Period {83 114} KP_Period {83 115} KP_Period {83 116} KP_Period {83 117} KP_Period {83 118} Boot {83 119} KP_Period {83 120} KP_Period {83 121} KP_Period {83 122} KP_Period {83 123} KP_Period {83 124} Boot {83 125} KP_Period {83 126} Boot {83 127} KP_Period {84 0} Last_Console {84 1} Last_Console {84 2} Last_Console {84 3} Last_Console {84 4} Last_Console {84 5} Last_Console {84 6} Last_Console {84 7} Last_Console {84 8} Last_Console {84 9} Last_Console {84 10} Last_Console {84 11} Last_Console {84 12} Last_Console {84 13} Last_Console {84 14} Last_Console {84 15} Last_Console {84 16} Last_Console {84 17} Last_Console {84 18} Last_Console {84 19} Last_Console {84 20} Last_Console {84 21} Last_Console {84 22} Last_Console {84 23} Last_Console {84 24} Last_Console {84 25} Last_Console {84 26} Last_Console {84 27} Last_Console {84 28} Last_Console {84 29} Last_Console {84 30} Last_Console {84 31} Last_Console {84 32} Last_Console {84 33} Last_Console {84 34} Last_Console {84 35} Last_Console {84 36} Last_Console {84 37} Last_Console {84 38} Last_Console {84 39} Last_Console {84 40} Last_Console {84 41} Last_Console {84 42} Last_Console {84 43} Last_Console {84 44} Last_Console {84 45} Last_Console {84 46} Last_Console {84 47} Last_Console {84 48} Last_Console {84 49} Last_Console {84 50} Last_Console {84 51} Last_Console {84 52} Last_Console {84 53} Last_Console {84 54} Last_Console {84 55} Last_Console {84 56} Last_Console {84 57} Last_Console {84 58} Last_Console {84 59} Last_Console {84 60} Last_Console {84 61} Last_Console {84 62} Last_Console {84 63} Last_Console {84 64} Last_Console {84 65} Last_Console {84 66} Last_Console {84 67} Last_Console {84 68} Last_Console {84 69} Last_Console {84 70} Last_Console {84 71} Last_Console {84 72} Last_Console {84 73} Last_Console {84 74} Last_Console {84 75} Last_Console {84 76} Last_Console {84 77} Last_Console {84 78} Last_Console {84 79} Last_Console {84 80} Last_Console {84 81} Last_Console {84 82} Last_Console {84 83} Last_Console {84 84} Last_Console {84 85} Last_Console {84 86} Last_Console {84 87} Last_Console {84 88} Last_Console {84 89} Last_Console {84 90} Last_Console {84 91} Last_Console {84 92} Last_Console {84 93} Last_Console {84 94} Last_Console {84 95} Last_Console {84 96} Last_Console {84 97} Last_Console {84 98} Last_Console {84 99} Last_Console {84 100} Last_Console {84 101} Last_Console {84 102} Last_Console {84 103} Last_Console {84 104} Last_Console {84 105} Last_Console {84 106} Last_Console {84 107} Last_Console {84 108} Last_Console {84 109} Last_Console {84 110} Last_Console {84 111} Last_Console {84 112} Last_Console {84 113} Last_Console {84 114} Last_Console {84 115} Last_Console {84 116} Last_Console {84 117} Last_Console {84 118} Last_Console {84 119} Last_Console {84 120} Last_Console {84 121} Last_Console {84 122} Last_Console {84 123} Last_Console {84 124} Last_Console {84 125} Last_Console {84 126} Last_Console {84 127} Last_Console {86 0} less {86 1} greater {86 2} bar {86 3} brokenbar {86 4} Control_backslash {86 5} greater {86 6} Control_backslash {86 7} Control_backslash {86 8} Meta_less {86 9} Meta_greater {86 10} Meta_bar {86 11} Meta_bar {86 12} Meta_Control_backslash {86 13} Meta_greater {86 14} Meta_Control_backslash {86 15} Meta_Control_backslash {86 16} less {86 17} greater {86 18} bar {86 19} brokenbar {86 20} Control_backslash {86 21} greater {86 22} Control_backslash {86 23} Control_backslash {86 24} Meta_less {86 25} Meta_greater {86 26} Meta_bar {86 27} Meta_bar {86 28} Meta_Control_backslash {86 29} Meta_greater {86 30} Meta_Control_backslash {86 31} Meta_Control_backslash {86 32} less {86 33} greater {86 34} bar {86 35} brokenbar {86 36} Control_backslash {86 37} greater {86 38} Control_backslash {86 39} Control_backslash {86 40} Meta_less {86 41} Meta_greater {86 42} Meta_bar {86 43} Meta_bar {86 44} Meta_Control_backslash {86 45} Meta_greater {86 46} Meta_Control_backslash {86 47} Meta_Control_backslash {86 48} less {86 49} greater {86 50} bar {86 51} brokenbar {86 52} Control_backslash {86 53} greater {86 54} Control_backslash {86 55} Control_backslash {86 56} Meta_less {86 57} Meta_greater {86 58} Meta_bar {86 59} Meta_bar {86 60} Meta_Control_backslash {86 61} Meta_greater {86 62} Meta_Control_backslash {86 63} Meta_Control_backslash {86 64} less {86 65} greater {86 66} bar {86 67} brokenbar {86 68} Control_backslash {86 69} greater {86 70} Control_backslash {86 71} Control_backslash {86 72} Meta_less {86 73} Meta_greater {86 74} Meta_bar {86 75} Meta_bar {86 76} Meta_Control_backslash {86 77} Meta_greater {86 78} Meta_Control_backslash {86 79} Meta_Control_backslash {86 80} less {86 81} greater {86 82} bar {86 83} brokenbar {86 84} Control_backslash {86 85} greater {86 86} Control_backslash {86 87} Control_backslash {86 88} Meta_less {86 89} Meta_greater {86 90} Meta_bar {86 91} Meta_bar {86 92} Meta_Control_backslash {86 93} Meta_greater {86 94} Meta_Control_backslash {86 95} Meta_Control_backslash {86 96} less {86 97} greater {86 98} bar {86 99} brokenbar {86 100} Control_backslash {86 101} greater {86 102} Control_backslash {86 103} Control_backslash {86 104} Meta_less {86 105} Meta_greater {86 106} Meta_bar {86 107} Meta_bar {86 108} Meta_Control_backslash {86 109} Meta_greater {86 110} Meta_Control_backslash {86 111} Meta_Control_backslash {86 112} less {86 113} greater {86 114} bar {86 115} brokenbar {86 116} Control_backslash {86 117} greater {86 118} Control_backslash {86 119} Control_backslash {86 120} Meta_less {86 121} Meta_greater {86 122} Meta_bar {86 123} Meta_bar {86 124} Meta_Control_backslash {86 125} Meta_greater {86 126} Meta_Control_backslash {86 127} Meta_Control_backslash {87 0} F11 {87 1} F23 {87 2} Console_23 {87 3} Console_35 {87 4} F35 {87 5} F47 {87 6} Console_23 {87 7} Console_35 {87 8} Console_11 {87 9} Console_23 {87 10} F11 {87 11} F11 {87 12} Console_11 {87 13} Console_23 {87 14} F11 {87 15} F11 {87 16} F11 {87 17} F23 {87 18} Console_23 {87 19} Console_35 {87 20} F35 {87 21} F47 {87 22} Console_23 {87 23} Console_35 {87 24} Console_11 {87 25} Console_23 {87 26} F11 {87 27} F11 {87 28} Console_11 {87 29} Console_23 {87 30} F11 {87 31} F11 {87 32} F11 {87 33} F23 {87 34} Console_23 {87 35} Console_35 {87 36} F35 {87 37} F47 {87 38} Console_23 {87 39} Console_35 {87 40} Console_11 {87 41} Console_23 {87 42} F11 {87 43} F11 {87 44} Console_11 {87 45} Console_23 {87 46} F11 {87 47} F11 {87 48} F11 {87 49} F23 {87 50} Console_23 {87 51} Console_35 {87 52} F35 {87 53} F47 {87 54} Console_23 {87 55} Console_35 {87 56} Console_11 {87 57} Console_23 {87 58} F11 {87 59} F11 {87 60} Console_11 {87 61} Console_23 {87 62} F11 {87 63} F11 {87 64} F11 {87 65} F23 {87 66} Console_23 {87 67} Console_35 {87 68} F35 {87 69} F47 {87 70} Console_23 {87 71} Console_35 {87 72} Console_11 {87 73} Console_23 {87 74} F11 {87 75} F11 {87 76} Console_11 {87 77} Console_23 {87 78} F11 {87 79} F11 {87 80} F11 {87 81} F23 {87 82} Console_23 {87 83} Console_35 {87 84} F35 {87 85} F47 {87 86} Console_23 {87 87} Console_35 {87 88} Console_11 {87 89} Console_23 {87 90} F11 {87 91} F11 {87 92} Console_11 {87 93} Console_23 {87 94} F11 {87 95} F11 {87 96} F11 {87 97} F23 {87 98} Console_23 {87 99} Console_35 {87 100} F35 {87 101} F47 {87 102} Console_23 {87 103} Console_35 {87 104} Console_11 {87 105} Console_23 {87 106} F11 {87 107} F11 {87 108} Console_11 {87 109} Console_23 {87 110} F11 {87 111} F11 {87 112} F11 {87 113} F23 {87 114} Console_23 {87 115} Console_35 {87 116} F35 {87 117} F47 {87 118} Console_23 {87 119} Console_35 {87 120} Console_11 {87 121} Console_23 {87 122} F11 {87 123} F11 {87 124} Console_11 {87 125} Console_23 {87 126} F11 {87 127} F11 {88 0} F12 {88 1} F24 {88 2} Console_24 {88 3} Console_36 {88 4} F36 {88 5} F48 {88 6} Console_24 {88 7} Console_36 {88 8} Console_12 {88 9} Console_24 {88 10} F12 {88 11} F12 {88 12} Console_12 {88 13} Console_24 {88 14} F12 {88 15} F12 {88 16} F12 {88 17} F24 {88 18} Console_24 {88 19} Console_36 {88 20} F36 {88 21} F48 {88 22} Console_24 {88 23} Console_36 {88 24} Console_12 {88 25} Console_24 {88 26} F12 {88 27} F12 {88 28} Console_12 {88 29} Console_24 {88 30} F12 {88 31} F12 {88 32} F12 {88 33} F24 {88 34} Console_24 {88 35} Console_36 {88 36} F36 {88 37} F48 {88 38} Console_24 {88 39} Console_36 {88 40} Console_12 {88 41} Console_24 {88 42} F12 {88 43} F12 {88 44} Console_12 {88 45} Console_24 {88 46} F12 {88 47} F12 {88 48} F12 {88 49} F24 {88 50} Console_24 {88 51} Console_36 {88 52} F36 {88 53} F48 {88 54} Console_24 {88 55} Console_36 {88 56} Console_12 {88 57} Console_24 {88 58} F12 {88 59} F12 {88 60} Console_12 {88 61} Console_24 {88 62} F12 {88 63} F12 {88 64} F12 {88 65} F24 {88 66} Console_24 {88 67} Console_36 {88 68} F36 {88 69} F48 {88 70} Console_24 {88 71} Console_36 {88 72} Console_12 {88 73} Console_24 {88 74} F12 {88 75} F12 {88 76} Console_12 {88 77} Console_24 {88 78} F12 {88 79} F12 {88 80} F12 {88 81} F24 {88 82} Console_24 {88 83} Console_36 {88 84} F36 {88 85} F48 {88 86} Console_24 {88 87} Console_36 {88 88} Console_12 {88 89} Console_24 {88 90} F12 {88 91} F12 {88 92} Console_12 {88 93} Console_24 {88 94} F12 {88 95} F12 {88 96} F12 {88 97} F24 {88 98} Console_24 {88 99} Console_36 {88 100} F36 {88 101} F48 {88 102} Console_24 {88 103} Console_36 {88 104} Console_12 {88 105} Console_24 {88 106} F12 {88 107} F12 {88 108} Console_12 {88 109} Console_24 {88 110} F12 {88 111} F12 {88 112} F12 {88 113} F24 {88 114} Console_24 {88 115} Console_36 {88 116} F36 {88 117} F48 {88 118} Console_24 {88 119} Console_36 {88 120} Console_12 {88 121} Console_24 {88 122} F12 {88 123} F12 {88 124} Console_12 {88 125} Console_24 {88 126} F12 {88 127} F12 {96 0} KP_Enter {96 1} KP_Enter {96 2} Hex_F {96 3} KP_Enter {96 4} KP_Enter {96 5} KP_Enter {96 6} KP_Enter {96 7} KP_Enter {96 8} KP_Enter {96 9} Hex_F {96 10} KP_Enter {96 11} KP_Enter {96 12} KP_Enter {96 13} KP_Enter {96 14} KP_Enter {96 15} KP_Enter {96 16} KP_Enter {96 17} KP_Enter {96 18} Hex_F {96 19} KP_Enter {96 20} KP_Enter {96 21} KP_Enter {96 22} KP_Enter {96 23} KP_Enter {96 24} KP_Enter {96 25} Hex_F {96 26} KP_Enter {96 27} KP_Enter {96 28} KP_Enter {96 29} KP_Enter {96 30} KP_Enter {96 31} KP_Enter {96 32} KP_Enter {96 33} KP_Enter {96 34} Hex_F {96 35} KP_Enter {96 36} KP_Enter {96 37} KP_Enter {96 38} KP_Enter {96 39} KP_Enter {96 40} KP_Enter {96 41} Hex_F {96 42} KP_Enter {96 43} KP_Enter {96 44} KP_Enter {96 45} KP_Enter {96 46} KP_Enter {96 47} KP_Enter {96 48} KP_Enter {96 49} KP_Enter {96 50} Hex_F {96 51} KP_Enter {96 52} KP_Enter {96 53} KP_Enter {96 54} KP_Enter {96 55} KP_Enter {96 56} KP_Enter {96 57} Hex_F {96 58} KP_Enter {96 59} KP_Enter {96 60} KP_Enter {96 61} KP_Enter {96 62} KP_Enter {96 63} KP_Enter {96 64} KP_Enter {96 65} KP_Enter {96 66} Hex_F {96 67} KP_Enter {96 68} KP_Enter {96 69} KP_Enter {96 70} KP_Enter {96 71} KP_Enter {96 72} KP_Enter {96 73} Hex_F {96 74} KP_Enter {96 75} KP_Enter {96 76} KP_Enter {96 77} KP_Enter {96 78} KP_Enter {96 79} KP_Enter {96 80} KP_Enter {96 81} KP_Enter {96 82} Hex_F {96 83} KP_Enter {96 84} KP_Enter {96 85} KP_Enter {96 86} KP_Enter {96 87} KP_Enter {96 88} KP_Enter {96 89} Hex_F {96 90} KP_Enter {96 91} KP_Enter {96 92} KP_Enter {96 93} KP_Enter {96 94} KP_Enter {96 95} KP_Enter {96 96} KP_Enter {96 97} KP_Enter {96 98} Hex_F {96 99} KP_Enter {96 100} KP_Enter {96 101} KP_Enter {96 102} KP_Enter {96 103} KP_Enter {96 104} KP_Enter {96 105} Hex_F {96 106} KP_Enter {96 107} KP_Enter {96 108} KP_Enter {96 109} KP_Enter {96 110} KP_Enter {96 111} KP_Enter {96 112} KP_Enter {96 113} KP_Enter {96 114} Hex_F {96 115} KP_Enter {96 116} KP_Enter {96 117} KP_Enter {96 118} KP_Enter {96 119} KP_Enter {96 120} KP_Enter {96 121} Hex_F {96 122} KP_Enter {96 123} KP_Enter {96 124} KP_Enter {96 125} KP_Enter {96 126} KP_Enter {96 127} KP_Enter {97 0} Control {97 1} Control {97 2} Control {97 3} Control {97 4} Control {97 5} Control {97 6} Control {97 7} Control {97 8} Control {97 9} Control {97 10} Control {97 11} Control {97 12} Control {97 13} Control {97 14} Control {97 15} Control {97 16} Control {97 17} Control {97 18} Control {97 19} Control {97 20} Control {97 21} Control {97 22} Control {97 23} Control {97 24} Control {97 25} Control {97 26} Control {97 27} Control {97 28} Control {97 29} Control {97 30} Control {97 31} Control {97 32} Control {97 33} Control {97 34} Control {97 35} Control {97 36} Control {97 37} Control {97 38} Control {97 39} Control {97 40} Control {97 41} Control {97 42} Control {97 43} Control {97 44} Control {97 45} Control {97 46} Control {97 47} Control {97 48} Control {97 49} Control {97 50} Control {97 51} Control {97 52} Control {97 53} Control {97 54} Control {97 55} Control {97 56} Control {97 57} Control {97 58} Control {97 59} Control {97 60} Control {97 61} Control {97 62} Control {97 63} Control {97 64} Control {97 65} Control {97 66} Control {97 67} Control {97 68} Control {97 69} Control {97 70} Control {97 71} Control {97 72} Control {97 73} Control {97 74} Control {97 75} Control {97 76} Control {97 77} Control {97 78} Control {97 79} Control {97 80} Control {97 81} Control {97 82} Control {97 83} Control {97 84} Control {97 85} Control {97 86} Control {97 87} Control {97 88} Control {97 89} Control {97 90} Control {97 91} Control {97 92} Control {97 93} Control {97 94} Control {97 95} Control {97 96} Control {97 97} Control {97 98} Control {97 99} Control {97 100} Control {97 101} Control {97 102} Control {97 103} Control {97 104} Control {97 105} Control {97 106} Control {97 107} Control {97 108} Control {97 109} Control {97 110} Control {97 111} Control {97 112} Control {97 113} Control {97 114} Control {97 115} Control {97 116} Control {97 117} Control {97 118} Control {97 119} Control {97 120} Control {97 121} Control {97 122} Control {97 123} Control {97 124} Control {97 125} Control {97 126} Control {97 127} Control {98 0} KP_Divide {98 1} KP_Divide {98 2} Hex_B {98 3} KP_Divide {98 4} KP_Divide {98 5} KP_Divide {98 6} KP_Divide {98 7} KP_Divide {98 8} KP_Divide {98 9} Hex_B {98 10} KP_Divide {98 11} KP_Divide {98 12} KP_Divide {98 13} KP_Divide {98 14} KP_Divide {98 15} KP_Divide {98 16} KP_Divide {98 17} KP_Divide {98 18} Hex_B {98 19} KP_Divide {98 20} KP_Divide {98 21} KP_Divide {98 22} KP_Divide {98 23} KP_Divide {98 24} KP_Divide {98 25} Hex_B {98 26} KP_Divide {98 27} KP_Divide {98 28} KP_Divide {98 29} KP_Divide {98 30} KP_Divide {98 31} KP_Divide {98 32} KP_Divide {98 33} KP_Divide {98 34} Hex_B {98 35} KP_Divide {98 36} KP_Divide {98 37} KP_Divide {98 38} KP_Divide {98 39} KP_Divide {98 40} KP_Divide {98 41} Hex_B {98 42} KP_Divide {98 43} KP_Divide {98 44} KP_Divide {98 45} KP_Divide {98 46} KP_Divide {98 47} KP_Divide {98 48} KP_Divide {98 49} KP_Divide {98 50} Hex_B {98 51} KP_Divide {98 52} KP_Divide {98 53} KP_Divide {98 54} KP_Divide {98 55} KP_Divide {98 56} KP_Divide {98 57} Hex_B {98 58} KP_Divide {98 59} KP_Divide {98 60} KP_Divide {98 61} KP_Divide {98 62} KP_Divide {98 63} KP_Divide {98 64} KP_Divide {98 65} KP_Divide {98 66} Hex_B {98 67} KP_Divide {98 68} KP_Divide {98 69} KP_Divide {98 70} KP_Divide {98 71} KP_Divide {98 72} KP_Divide {98 73} Hex_B {98 74} KP_Divide {98 75} KP_Divide {98 76} KP_Divide {98 77} KP_Divide {98 78} KP_Divide {98 79} KP_Divide {98 80} KP_Divide {98 81} KP_Divide {98 82} Hex_B {98 83} KP_Divide {98 84} KP_Divide {98 85} KP_Divide {98 86} KP_Divide {98 87} KP_Divide {98 88} KP_Divide {98 89} Hex_B {98 90} KP_Divide {98 91} KP_Divide {98 92} KP_Divide {98 93} KP_Divide {98 94} KP_Divide {98 95} KP_Divide {98 96} KP_Divide {98 97} KP_Divide {98 98} Hex_B {98 99} KP_Divide {98 100} KP_Divide {98 101} KP_Divide {98 102} KP_Divide {98 103} KP_Divide {98 104} KP_Divide {98 105} Hex_B {98 106} KP_Divide {98 107} KP_Divide {98 108} KP_Divide {98 109} KP_Divide {98 110} KP_Divide {98 111} KP_Divide {98 112} KP_Divide {98 113} KP_Divide {98 114} Hex_B {98 115} KP_Divide {98 116} KP_Divide {98 117} KP_Divide {98 118} KP_Divide {98 119} KP_Divide {98 120} KP_Divide {98 121} Hex_B {98 122} KP_Divide {98 123} KP_Divide {98 124} KP_Divide {98 125} KP_Divide {98 126} KP_Divide {98 127} KP_Divide {99 0} Control_backslash {99 1} Control_backslash {99 2} Control_backslash {99 3} Control_backslash {99 4} Control_backslash {99 5} Control_backslash {99 6} Last_Console {99 7} Last_Console {99 8} Last_Console {99 9} Last_Console {99 10} Meta_Control_backslash {99 11} Meta_Control_backslash {99 12} Meta_Control_backslash {99 13} Meta_Control_backslash {99 14} Control_backslash {99 15} Control_backslash {99 16} Control_backslash {99 17} Control_backslash {99 18} Control_backslash {99 19} Control_backslash {99 20} Last_Console {99 21} Last_Console {99 22} Last_Console {99 23} Last_Console {99 24} Meta_Control_backslash {99 25} Meta_Control_backslash {99 26} Meta_Control_backslash {99 27} Meta_Control_backslash {99 28} Control_backslash {99 29} Control_backslash {99 30} Control_backslash {99 31} Control_backslash {99 32} Control_backslash {99 33} Control_backslash {99 34} Last_Console {99 35} Last_Console {99 36} Last_Console {99 37} Last_Console {99 38} Meta_Control_backslash {99 39} Meta_Control_backslash {99 40} Meta_Control_backslash {99 41} Meta_Control_backslash {99 42} Control_backslash {99 43} Control_backslash {99 44} Control_backslash {99 45} Control_backslash {99 46} Control_backslash {99 47} Control_backslash {99 48} Last_Console {99 49} Last_Console {99 50} Last_Console {99 51} Last_Console {99 52} Meta_Control_backslash {99 53} Meta_Control_backslash {99 54} Meta_Control_backslash {99 55} Meta_Control_backslash {99 56} Control_backslash {99 57} Control_backslash {99 58} Control_backslash {99 59} Control_backslash {99 60} Control_backslash {99 61} Control_backslash {99 62} Last_Console {99 63} Last_Console {99 64} Last_Console {99 65} Last_Console {99 66} Meta_Control_backslash {99 67} Meta_Control_backslash {99 68} Meta_Control_backslash {99 69} Meta_Control_backslash {99 70} Control_backslash {99 71} Control_backslash {99 72} Control_backslash {99 73} Control_backslash {99 74} Control_backslash {99 75} Control_backslash {99 76} Last_Console {99 77} Last_Console {99 78} Last_Console {99 79} Last_Console {99 80} Meta_Control_backslash {99 81} Meta_Control_backslash {99 82} Meta_Control_backslash {99 83} Meta_Control_backslash {99 84} Control_backslash {99 85} Control_backslash {99 86} Control_backslash {99 87} Control_backslash {99 88} Control_backslash {99 89} Control_backslash {99 90} Last_Console {99 91} Last_Console {99 92} Last_Console {99 93} Last_Console {99 94} Meta_Control_backslash {99 95} Meta_Control_backslash {99 96} Meta_Control_backslash {99 97} Meta_Control_backslash {99 98} Control_backslash {99 99} Control_backslash {99 100} Control_backslash {99 101} Control_backslash {99 102} Control_backslash {99 103} Control_backslash {99 104} Last_Console {99 105} Last_Console {99 106} Last_Console {99 107} Last_Console {99 108} Meta_Control_backslash {99 109} Meta_Control_backslash {99 110} Meta_Control_backslash {99 111} Meta_Control_backslash {100 0} Alt {100 1} Alt {100 2} Alt {100 3} Alt {100 4} Alt {100 5} Alt {100 6} Alt {100 7} Alt {100 8} Alt {100 9} Alt {100 10} Alt {100 11} Alt {100 12} Alt {100 13} Alt {100 14} Alt {100 15} Alt {100 16} Alt {100 17} Alt {100 18} Alt {100 19} Alt {100 20} Alt {100 21} Alt {100 22} Alt {100 23} Alt {100 24} Alt {100 25} Alt {100 26} Alt {100 27} Alt {100 28} Alt {100 29} Alt {100 30} Alt {100 31} Alt {100 32} Alt {100 33} Alt {100 34} Alt {100 35} Alt {100 36} Alt {100 37} Alt {100 38} Alt {100 39} Alt {100 40} Alt {100 41} Alt {100 42} Alt {100 43} Alt {100 44} Alt {100 45} Alt {100 46} Alt {100 47} Alt {100 48} Alt {100 49} Alt {100 50} Alt {100 51} Alt {100 52} Alt {100 53} Alt {100 54} Alt {100 55} Alt {100 56} Alt {100 57} Alt {100 58} Alt {100 59} Alt {100 60} Alt {100 61} Alt {100 62} Alt {100 63} Alt {100 64} Alt {100 65} Alt {100 66} Alt {100 67} Alt {100 68} Alt {100 69} Alt {100 70} Alt {100 71} Alt {100 72} Alt {100 73} Alt {100 74} Alt {100 75} Alt {100 76} Alt {100 77} Alt {100 78} Alt {100 79} Alt {100 80} Alt {100 81} Alt {100 82} Alt {100 83} Alt {100 84} Alt {100 85} Alt {100 86} Alt {100 87} Alt {100 88} Alt {100 89} Alt {100 90} Alt {100 91} Alt {100 92} Alt {100 93} Alt {100 94} Alt {100 95} Alt {100 96} Alt {100 97} Alt {100 98} Alt {100 99} Alt {100 100} Alt {100 101} Alt {100 102} Alt {100 103} Alt {100 104} Alt {100 105} Alt {100 106} Alt {100 107} Alt {100 108} Alt {100 109} Alt {100 110} Alt {100 111} Alt {100 112} Alt {100 113} Alt {100 114} Alt {100 115} Alt {100 116} Alt {100 117} Alt {100 118} Alt {100 119} Alt {100 120} Alt {100 121} Alt {100 122} Alt {100 123} Alt {100 124} Alt {100 125} Alt {100 126} Alt {100 127} Alt {101 0} Break {101 1} Break {101 2} Break {101 3} Break {101 4} Break {101 5} Break {101 6} Break {101 7} Break {101 8} Break {101 9} Break {101 10} Break {101 11} Break {101 12} Break {101 13} Break {101 14} Break {101 15} Break {101 16} Break {101 17} Break {101 18} Break {101 19} Break {101 20} Break {101 21} Break {101 22} Break {101 23} Break {101 24} Break {101 25} Break {101 26} Break {101 27} Break {101 28} Break {101 29} Break {101 30} Break {101 31} Break {101 32} Break {101 33} Break {101 34} Break {101 35} Break {101 36} Break {101 37} Break {101 38} Break {101 39} Break {101 40} Break {101 41} Break {101 42} Break {101 43} Break {101 44} Break {101 45} Break {101 46} Break {101 47} Break {101 48} Break {101 49} Break {101 50} Break {101 51} Break {101 52} Break {101 53} Break {101 54} Break {101 55} Break {101 56} Break {101 57} Break {101 58} Break {101 59} Break {101 60} Break {101 61} Break {101 62} Break {101 63} Break {101 64} Break {101 65} Break {101 66} Break {101 67} Break {101 68} Break {101 69} Break {101 70} Break {101 71} Break {101 72} Break {101 73} Break {101 74} Break {101 75} Break {101 76} Break {101 77} Break {101 78} Break {101 79} Break {101 80} Break {101 81} Break {101 82} Break {101 83} Break {101 84} Break {101 85} Break {101 86} Break {101 87} Break {101 88} Break {101 89} Break {101 90} Break {101 91} Break {101 92} Break {101 93} Break {101 94} Break {101 95} Break {101 96} Break {101 97} Break {101 98} Break {101 99} Break {101 100} Break {101 101} Break {101 102} Break {101 103} Break {101 104} Break {101 105} Break {101 106} Break {101 107} Break {101 108} Break {101 109} Break {101 110} Break {101 111} Break {101 112} Break {101 113} Break {101 114} Break {101 115} Break {101 116} Break {101 117} Break {101 118} Break {101 119} Break {101 120} Break {101 121} Break {101 122} Break {101 123} Break {101 124} Break {101 125} Break {101 126} Break {101 127} Break {102 0} Find {102 1} Find {102 2} Find {102 3} Find {102 4} Find {102 5} Find {102 6} Find {102 7} Find {102 8} Find {102 9} Find {102 10} Find {102 11} Find {102 12} Find {102 13} Find {102 14} Find {102 15} Find {102 16} Find {102 17} Find {102 18} Find {102 19} Find {102 20} Find {102 21} Find {102 22} Find {102 23} Find {102 24} Find {102 25} Find {102 26} Find {102 27} Find {102 28} Find {102 29} Find {102 30} Find {102 31} Find {102 32} Find {102 33} Find {102 34} Find {102 35} Find {102 36} Find {102 37} Find {102 38} Find {102 39} Find {102 40} Find {102 41} Find {102 42} Find {102 43} Find {102 44} Find {102 45} Find {102 46} Find {102 47} Find {102 48} Find {102 49} Find {102 50} Find {102 51} Find {102 52} Find {102 53} Find {102 54} Find {102 55} Find {102 56} Find {102 57} Find {102 58} Find {102 59} Find {102 60} Find {102 61} Find {102 62} Find {102 63} Find {102 64} Find {102 65} Find {102 66} Find {102 67} Find {102 68} Find {102 69} Find {102 70} Find {102 71} Find {102 72} Find {102 73} Find {102 74} Find {102 75} Find {102 76} Find {102 77} Find {102 78} Find {102 79} Find {102 80} Find {102 81} Find {102 82} Find {102 83} Find {102 84} Find {102 85} Find {102 86} Find {102 87} Find {102 88} Find {102 89} Find {102 90} Find {102 91} Find {102 92} Find {102 93} Find {102 94} Find {102 95} Find {102 96} Find {102 97} Find {102 98} Find {102 99} Find {102 100} Find {102 101} Find {102 102} Find {102 103} Find {102 104} Find {102 105} Find {102 106} Find {102 107} Find {102 108} Find {102 109} Find {102 110} Find {102 111} Find {102 112} Find {102 113} Find {102 114} Find {102 115} Find {102 116} Find {102 117} Find {102 118} Find {102 119} Find {102 120} Find {102 121} Find {102 122} Find {102 123} Find {102 124} Find {102 125} Find {102 126} Find {102 127} Find {103 0} Up {103 1} Up {103 2} Up {103 3} Up {103 4} Up {103 5} Up {103 6} Up {103 7} Up {103 8} KeyboardSignal {103 9} Up {103 10} Up {103 11} Up {103 12} Up {103 13} Up {103 14} Up {103 15} Up {103 16} Up {103 17} Up {103 18} Up {103 19} Up {103 20} Up {103 21} Up {103 22} Up {103 23} Up {103 24} KeyboardSignal {103 25} Up {103 26} Up {103 27} Up {103 28} Up {103 29} Up {103 30} Up {103 31} Up {103 32} Up {103 33} Up {103 34} Up {103 35} Up {103 36} Up {103 37} Up {103 38} Up {103 39} Up {103 40} KeyboardSignal {103 41} Up {103 42} Up {103 43} Up {103 44} Up {103 45} Up {103 46} Up {103 47} Up {103 48} Up {103 49} Up {103 50} Up {103 51} Up {103 52} Up {103 53} Up {103 54} Up {103 55} Up {103 56} KeyboardSignal {103 57} Up {103 58} Up {103 59} Up {103 60} Up {103 61} Up {103 62} Up {103 63} Up {103 64} Up {103 65} Up {103 66} Up {103 67} Up {103 68} Up {103 69} Up {103 70} Up {103 71} Up {103 72} KeyboardSignal {103 73} Up {103 74} Up {103 75} Up {103 76} Up {103 77} Up {103 78} Up {103 79} Up {103 80} Up {103 81} Up {103 82} Up {103 83} Up {103 84} Up {103 85} Up {103 86} Up {103 87} Up {103 88} KeyboardSignal {103 89} Up {103 90} Up {103 91} Up {103 92} Up {103 93} Up {103 94} Up {103 95} Up {103 96} Up {103 97} Up {103 98} Up {103 99} Up {103 100} Up {103 101} Up {103 102} Up {103 103} Up {103 104} KeyboardSignal {103 105} Up {103 106} Up {103 107} Up {103 108} Up {103 109} Up {103 110} Up {103 111} Up {103 112} Up {103 113} Up {103 114} Up {103 115} Up {103 116} Up {103 117} Up {103 118} Up {103 119} Up {103 120} KeyboardSignal {103 121} Up {103 122} Up {103 123} Up {103 124} Up {103 125} Up {103 126} Up {103 127} Up {104 0} Prior {104 1} Scroll_Backward {104 2} Prior {104 3} Prior {104 4} Prior {104 5} Prior {104 6} Prior {104 7} Prior {104 8} Prior {104 9} Prior {104 10} Prior {104 11} Prior {104 12} Prior {104 13} Prior {104 14} Prior {104 15} Prior {104 16} Prior {104 17} Scroll_Backward {104 18} Prior {104 19} Prior {104 20} Prior {104 21} Prior {104 22} Prior {104 23} Prior {104 24} Prior {104 25} Prior {104 26} Prior {104 27} Prior {104 28} Prior {104 29} Prior {104 30} Prior {104 31} Prior {104 32} Prior {104 33} Scroll_Backward {104 34} Prior {104 35} Prior {104 36} Prior {104 37} Prior {104 38} Prior {104 39} Prior {104 40} Prior {104 41} Prior {104 42} Prior {104 43} Prior {104 44} Prior {104 45} Prior {104 46} Prior {104 47} Prior {104 48} Prior {104 49} Scroll_Backward {104 50} Prior {104 51} Prior {104 52} Prior {104 53} Prior {104 54} Prior {104 55} Prior {104 56} Prior {104 57} Prior {104 58} Prior {104 59} Prior {104 60} Prior {104 61} Prior {104 62} Prior {104 63} Prior {104 64} Prior {104 65} Scroll_Backward {104 66} Prior {104 67} Prior {104 68} Prior {104 69} Prior {104 70} Prior {104 71} Prior {104 72} Prior {104 73} Prior {104 74} Prior {104 75} Prior {104 76} Prior {104 77} Prior {104 78} Prior {104 79} Prior {104 80} Prior {104 81} Scroll_Backward {104 82} Prior {104 83} Prior {104 84} Prior {104 85} Prior {104 86} Prior {104 87} Prior {104 88} Prior {104 89} Prior {104 90} Prior {104 91} Prior {104 92} Prior {104 93} Prior {104 94} Prior {104 95} Prior {104 96} Prior {104 97} Scroll_Backward {104 98} Prior {104 99} Prior {104 100} Prior {104 101} Prior {104 102} Prior {104 103} Prior {104 104} Prior {104 105} Prior {104 106} Prior {104 107} Prior {104 108} Prior {104 109} Prior {104 110} Prior {104 111} Prior {104 112} Prior {104 113} Scroll_Backward {104 114} Prior {104 115} Prior {104 116} Prior {104 117} Prior {104 118} Prior {104 119} Prior {104 120} Prior {104 121} Prior {104 122} Prior {104 123} Prior {104 124} Prior {104 125} Prior {104 126} Prior {104 127} Prior {105 0} Left {105 1} Left {105 2} Left {105 3} Left {105 4} Left {105 5} Left {105 6} Left {105 7} Left {105 8} Decr_Console {105 9} Left {105 10} Left {105 11} Left {105 12} Left {105 13} Left {105 14} Left {105 15} Left {105 16} Left {105 17} Left {105 18} Left {105 19} Left {105 20} Left {105 21} Left {105 22} Left {105 23} Left {105 24} Decr_Console {105 25} Left {105 26} Left {105 27} Left {105 28} Left {105 29} Left {105 30} Left {105 31} Left {105 32} Left {105 33} Left {105 34} Left {105 35} Left {105 36} Left {105 37} Left {105 38} Left {105 39} Left {105 40} Decr_Console {105 41} Left {105 42} Left {105 43} Left {105 44} Left {105 45} Left {105 46} Left {105 47} Left {105 48} Left {105 49} Left {105 50} Left {105 51} Left {105 52} Left {105 53} Left {105 54} Left {105 55} Left {105 56} Decr_Console {105 57} Left {105 58} Left {105 59} Left {105 60} Left {105 61} Left {105 62} Left {105 63} Left {105 64} Left {105 65} Left {105 66} Left {105 67} Left {105 68} Left {105 69} Left {105 70} Left {105 71} Left {105 72} Decr_Console {105 73} Left {105 74} Left {105 75} Left {105 76} Left {105 77} Left {105 78} Left {105 79} Left {105 80} Left {105 81} Left {105 82} Left {105 83} Left {105 84} Left {105 85} Left {105 86} Left {105 87} Left {105 88} Decr_Console {105 89} Left {105 90} Left {105 91} Left {105 92} Left {105 93} Left {105 94} Left {105 95} Left {105 96} Left {105 97} Left {105 98} Left {105 99} Left {105 100} Left {105 101} Left {105 102} Left {105 103} Left {105 104} Decr_Console {105 105} Left {105 106} Left {105 107} Left {105 108} Left {105 109} Left {105 110} Left {105 111} Left {105 112} Left {105 113} Left {105 114} Left {105 115} Left {105 116} Left {105 117} Left {105 118} Left {105 119} Left {105 120} Decr_Console {105 121} Left {105 122} Left {105 123} Left {105 124} Left {105 125} Left {105 126} Left {105 127} Left {106 0} Right {106 1} Right {106 2} Right {106 3} Right {106 4} Right {106 5} Right {106 6} Right {106 7} Right {106 8} Incr_Console {106 9} Right {106 10} Right {106 11} Right {106 12} Right {106 13} Right {106 14} Right {106 15} Right {106 16} Right {106 17} Right {106 18} Right {106 19} Right {106 20} Right {106 21} Right {106 22} Right {106 23} Right {106 24} Incr_Console {106 25} Right {106 26} Right {106 27} Right {106 28} Right {106 29} Right {106 30} Right {106 31} Right {106 32} Right {106 33} Right {106 34} Right {106 35} Right {106 36} Right {106 37} Right {106 38} Right {106 39} Right {106 40} Incr_Console {106 41} Right {106 42} Right {106 43} Right {106 44} Right {106 45} Right {106 46} Right {106 47} Right {106 48} Right {106 49} Right {106 50} Right {106 51} Right {106 52} Right {106 53} Right {106 54} Right {106 55} Right {106 56} Incr_Console {106 57} Right {106 58} Right {106 59} Right {106 60} Right {106 61} Right {106 62} Right {106 63} Right {106 64} Right {106 65} Right {106 66} Right {106 67} Right {106 68} Right {106 69} Right {106 70} Right {106 71} Right {106 72} Incr_Console {106 73} Right {106 74} Right {106 75} Right {106 76} Right {106 77} Right {106 78} Right {106 79} Right {106 80} Right {106 81} Right {106 82} Right {106 83} Right {106 84} Right {106 85} Right {106 86} Right {106 87} Right {106 88} Incr_Console {106 89} Right {106 90} Right {106 91} Right {106 92} Right {106 93} Right {106 94} Right {106 95} Right {106 96} Right {106 97} Right {106 98} Right {106 99} Right {106 100} Right {106 101} Right {106 102} Right {106 103} Right {106 104} Incr_Console {106 105} Right {106 106} Right {106 107} Right {106 108} Right {106 109} Right {106 110} Right {106 111} Right {106 112} Right {106 113} Right {106 114} Right {106 115} Right {106 116} Right {106 117} Right {106 118} Right {106 119} Right {106 120} Incr_Console {106 121} Right {106 122} Right {106 123} Right {106 124} Right {106 125} Right {106 126} Right {106 127} Right {107 0} Select {107 1} Select {107 2} Select {107 3} Select {107 4} Select {107 5} Select {107 6} Select {107 7} Select {107 8} Select {107 9} Select {107 10} Select {107 11} Select {107 12} Select {107 13} Select {107 14} Select {107 15} Select {107 16} Select {107 17} Select {107 18} Select {107 19} Select {107 20} Select {107 21} Select {107 22} Select {107 23} Select {107 24} Select {107 25} Select {107 26} Select {107 27} Select {107 28} Select {107 29} Select {107 30} Select {107 31} Select {107 32} Select {107 33} Select {107 34} Select {107 35} Select {107 36} Select {107 37} Select {107 38} Select {107 39} Select {107 40} Select {107 41} Select {107 42} Select {107 43} Select {107 44} Select {107 45} Select {107 46} Select {107 47} Select {107 48} Select {107 49} Select {107 50} Select {107 51} Select {107 52} Select {107 53} Select {107 54} Select {107 55} Select {107 56} Select {107 57} Select {107 58} Select {107 59} Select {107 60} Select {107 61} Select {107 62} Select {107 63} Select {107 64} Select {107 65} Select {107 66} Select {107 67} Select {107 68} Select {107 69} Select {107 70} Select {107 71} Select {107 72} Select {107 73} Select {107 74} Select {107 75} Select {107 76} Select {107 77} Select {107 78} Select {107 79} Select {107 80} Select {107 81} Select {107 82} Select {107 83} Select {107 84} Select {107 85} Select {107 86} Select {107 87} Select {107 88} Select {107 89} Select {107 90} Select {107 91} Select {107 92} Select {107 93} Select {107 94} Select {107 95} Select {107 96} Select {107 97} Select {107 98} Select {107 99} Select {107 100} Select {107 101} Select {107 102} Select {107 103} Select {107 104} Select {107 105} Select {107 106} Select {107 107} Select {107 108} Select {107 109} Select {107 110} Select {107 111} Select {107 112} Select {107 113} Select {107 114} Select {107 115} Select {107 116} Select {107 117} Select {107 118} Select {107 119} Select {107 120} Select {107 121} Select {107 122} Select {107 123} Select {107 124} Select {107 125} Select {107 126} Select {107 127} Select {108 0} Down {108 1} Down {108 2} Down {108 3} Down {108 4} Down {108 5} Down {108 6} Down {108 7} Down {108 8} Down {108 9} Down {108 10} Down {108 11} Down {108 12} Down {108 13} Down {108 14} Down {108 15} Down {108 16} Down {108 17} Down {108 18} Down {108 19} Down {108 20} Down {108 21} Down {108 22} Down {108 23} Down {108 24} Down {108 25} Down {108 26} Down {108 27} Down {108 28} Down {108 29} Down {108 30} Down {108 31} Down {108 32} Down {108 33} Down {108 34} Down {108 35} Down {108 36} Down {108 37} Down {108 38} Down {108 39} Down {108 40} Down {108 41} Down {108 42} Down {108 43} Down {108 44} Down {108 45} Down {108 46} Down {108 47} Down {108 48} Down {108 49} Down {108 50} Down {108 51} Down {108 52} Down {108 53} Down {108 54} Down {108 55} Down {108 56} Down {108 57} Down {108 58} Down {108 59} Down {108 60} Down {108 61} Down {108 62} Down {108 63} Down {108 64} Down {108 65} Down {108 66} Down {108 67} Down {108 68} Down {108 69} Down {108 70} Down {108 71} Down {108 72} Down {108 73} Down {108 74} Down {108 75} Down {108 76} Down {108 77} Down {108 78} Down {108 79} Down {108 80} Down {108 81} Down {108 82} Down {108 83} Down {108 84} Down {108 85} Down {108 86} Down {108 87} Down {108 88} Down {108 89} Down {108 90} Down {108 91} Down {108 92} Down {108 93} Down {108 94} Down {108 95} Down {108 96} Down {108 97} Down {108 98} Down {108 99} Down {108 100} Down {108 101} Down {108 102} Down {108 103} Down {108 104} Down {108 105} Down {108 106} Down {108 107} Down {108 108} Down {108 109} Down {108 110} Down {108 111} Down {108 112} Down {108 113} Down {108 114} Down {108 115} Down {108 116} Down {108 117} Down {108 118} Down {108 119} Down {108 120} Down {108 121} Down {108 122} Down {108 123} Down {108 124} Down {108 125} Down {108 126} Down {108 127} Down {109 0} Next {109 1} Scroll_Forward {109 2} Next {109 3} Next {109 4} Next {109 5} Next {109 6} Next {109 7} Next {109 8} Next {109 9} Next {109 10} Next {109 11} Next {109 12} Next {109 13} Next {109 14} Next {109 15} Next {109 16} Next {109 17} Scroll_Forward {109 18} Next {109 19} Next {109 20} Next {109 21} Next {109 22} Next {109 23} Next {109 24} Next {109 25} Next {109 26} Next {109 27} Next {109 28} Next {109 29} Next {109 30} Next {109 31} Next {109 32} Next {109 33} Scroll_Forward {109 34} Next {109 35} Next {109 36} Next {109 37} Next {109 38} Next {109 39} Next {109 40} Next {109 41} Next {109 42} Next {109 43} Next {109 44} Next {109 45} Next {109 46} Next {109 47} Next {109 48} Next {109 49} Scroll_Forward {109 50} Next {109 51} Next {109 52} Next {109 53} Next {109 54} Next {109 55} Next {109 56} Next {109 57} Next {109 58} Next {109 59} Next {109 60} Next {109 61} Next {109 62} Next {109 63} Next {109 64} Next {109 65} Scroll_Forward {109 66} Next {109 67} Next {109 68} Next {109 69} Next {109 70} Next {109 71} Next {109 72} Next {109 73} Next {109 74} Next {109 75} Next {109 76} Next {109 77} Next {109 78} Next {109 79} Next {109 80} Next {109 81} Scroll_Forward {109 82} Next {109 83} Next {109 84} Next {109 85} Next {109 86} Next {109 87} Next {109 88} Next {109 89} Next {109 90} Next {109 91} Next {109 92} Next {109 93} Next {109 94} Next {109 95} Next {109 96} Next {109 97} Scroll_Forward {109 98} Next {109 99} Next {109 100} Next {109 101} Next {109 102} Next {109 103} Next {109 104} Next {109 105} Next {109 106} Next {109 107} Next {109 108} Next {109 109} Next {109 110} Next {109 111} Next {109 112} Next {109 113} Scroll_Forward {109 114} Next {109 115} Next {109 116} Next {109 117} Next {109 118} Next {109 119} Next {109 120} Next {109 121} Next {109 122} Next {109 123} Next {109 124} Next {109 125} Next {109 126} Next {109 127} Next {110 0} Insert {110 1} Insert {110 2} Insert {110 3} Insert {110 4} Insert {110 5} Insert {110 6} Insert {110 7} Insert {110 8} Insert {110 9} Insert {110 10} Insert {110 11} Insert {110 12} Insert {110 13} Insert {110 14} Insert {110 15} Insert {110 16} Insert {110 17} Insert {110 18} Insert {110 19} Insert {110 20} Insert {110 21} Insert {110 22} Insert {110 23} Insert {110 24} Insert {110 25} Insert {110 26} Insert {110 27} Insert {110 28} Insert {110 29} Insert {110 30} Insert {110 31} Insert {110 32} Insert {110 33} Insert {110 34} Insert {110 35} Insert {110 36} Insert {110 37} Insert {110 38} Insert {110 39} Insert {110 40} Insert {110 41} Insert {110 42} Insert {110 43} Insert {110 44} Insert {110 45} Insert {110 46} Insert {110 47} Insert {110 48} Insert {110 49} Insert {110 50} Insert {110 51} Insert {110 52} Insert {110 53} Insert {110 54} Insert {110 55} Insert {110 56} Insert {110 57} Insert {110 58} Insert {110 59} Insert {110 60} Insert {110 61} Insert {110 62} Insert {110 63} Insert {110 64} Insert {110 65} Insert {110 66} Insert {110 67} Insert {110 68} Insert {110 69} Insert {110 70} Insert {110 71} Insert {110 72} Insert {110 73} Insert {110 74} Insert {110 75} Insert {110 76} Insert {110 77} Insert {110 78} Insert {110 79} Insert {110 80} Insert {110 81} Insert {110 82} Insert {110 83} Insert {110 84} Insert {110 85} Insert {110 86} Insert {110 87} Insert {110 88} Insert {110 89} Insert {110 90} Insert {110 91} Insert {110 92} Insert {110 93} Insert {110 94} Insert {110 95} Insert {110 96} Insert {110 97} Insert {110 98} Insert {110 99} Insert {110 100} Insert {110 101} Insert {110 102} Insert {110 103} Insert {110 104} Insert {110 105} Insert {110 106} Insert {110 107} Insert {110 108} Insert {110 109} Insert {110 110} Insert {110 111} Insert {110 112} Insert {110 113} Insert {110 114} Insert {110 115} Insert {110 116} Insert {110 117} Insert {110 118} Insert {110 119} Insert {110 120} Insert {110 121} Insert {110 122} Insert {110 123} Insert {110 124} Insert {110 125} Insert {110 126} Insert {110 127} Insert {111 0} Remove {111 1} Remove {111 2} Remove {111 3} Remove {111 4} Remove {111 5} Remove {111 6} Boot {111 7} Remove {111 8} Remove {111 9} Remove {111 10} Remove {111 11} Remove {111 12} Boot {111 13} Remove {111 14} Boot {111 15} Remove {111 16} Remove {111 17} Remove {111 18} Remove {111 19} Remove {111 20} Remove {111 21} Remove {111 22} Boot {111 23} Remove {111 24} Remove {111 25} Remove {111 26} Remove {111 27} Remove {111 28} Boot {111 29} Remove {111 30} Boot {111 31} Remove {111 32} Remove {111 33} Remove {111 34} Remove {111 35} Remove {111 36} Remove {111 37} Remove {111 38} Boot {111 39} Remove {111 40} Remove {111 41} Remove {111 42} Remove {111 43} Remove {111 44} Boot {111 45} Remove {111 46} Boot {111 47} Remove {111 48} Remove {111 49} Remove {111 50} Remove {111 51} Remove {111 52} Remove {111 53} Remove {111 54} Boot {111 55} Remove {111 56} Remove {111 57} Remove {111 58} Remove {111 59} Remove {111 60} Boot {111 61} Remove {111 62} Boot {111 63} Remove {111 64} Remove {111 65} Remove {111 66} Remove {111 67} Remove {111 68} Remove {111 69} Remove {111 70} Boot {111 71} Remove {111 72} Remove {111 73} Remove {111 74} Remove {111 75} Remove {111 76} Boot {111 77} Remove {111 78} Boot {111 79} Remove {111 80} Remove {111 81} Remove {111 82} Remove {111 83} Remove {111 84} Remove {111 85} Remove {111 86} Boot {111 87} Remove {111 88} Remove {111 89} Remove {111 90} Remove {111 91} Remove {111 92} Boot {111 93} Remove {111 94} Boot {111 95} Remove {111 96} Remove {111 97} Remove {111 98} Remove {111 99} Remove {111 100} Remove {111 101} Remove {111 102} Boot {111 103} Remove {111 104} Remove {111 105} Remove {111 106} Remove {111 107} Remove {111 108} Boot {111 109} Remove {111 110} Boot {111 111} Remove {111 112} Remove {111 113} Remove {111 114} Remove {111 115} Remove {111 116} Remove {111 117} Remove {111 118} Boot {111 119} Remove {111 120} Remove {111 121} Remove {111 122} Remove {111 123} Remove {111 124} Boot {111 125} Remove {111 126} Boot {111 127} Remove {112 0} Macro {112 1} Macro {112 2} Macro {112 3} Macro {112 4} Macro {112 5} Macro {112 6} Macro {113 0} F13 {113 1} F13 {113 2} F13 {113 3} F13 {113 4} F13 {113 5} F13 {113 6} F13 {114 0} F14 {114 1} F14 {114 2} F14 {114 3} F14 {114 4} F14 {114 5} F14 {114 6} F14 {115 0} Help {115 1} Help {115 2} Help {115 3} Help {115 4} Help {115 5} Help {115 6} Help {116 0} Do {116 1} Do {116 2} Do {116 3} Do {116 4} Do {116 5} Do {116 6} Do {117 0} F17 {117 1} F17 {117 2} F17 {117 3} F17 {117 4} F17 {117 5} F17 {117 6} F17 {118 0} KP_MinPlus {118 1} KP_MinPlus {118 2} KP_MinPlus {118 3} KP_MinPlus {118 4} KP_MinPlus {118 5} KP_MinPlus {118 6} KP_MinPlus {119 0} Pause {119 1} Pause {119 2} Pause {119 3} Pause {119 4} Break {119 5} Break {119 6} Break {119 7} Break {119 8} Pause {119 9} Pause {119 10} Pause {119 11} Pause {119 12} Break {119 13} Break {119 14} Break {119 15} Break {119 16} Pause {119 17} Pause {119 18} Pause {119 19} Pause {119 20} Break {119 21} Break {119 22} Break {119 23} Break {119 24} Pause {119 25} Pause {119 26} Pause {119 27} Pause {119 28} Break {119 29} Break {119 30} Break {119 31} Break {119 32} Pause {119 33} Pause {119 34} Pause {119 35} Pause {119 36} Break {119 37} Break {119 38} Break {119 39} Break {119 40} Pause {119 41} Pause {119 42} Pause {119 43} Pause {119 44} Break {119 45} Break {119 46} Break {119 47} Break {119 48} Pause {119 49} Pause {119 50} Pause {119 51} Pause {119 52} Break {119 53} Break {119 54} Break {119 55} Break {119 56} Pause {119 57} Pause {119 58} Pause {119 59} Pause {119 60} Break {119 61} Break {119 62} Break {119 63} Break {119 64} Pause {119 65} Pause {119 66} Pause {119 67} Pause {119 68} Break {119 69} Break {119 70} Break {119 71} Break {119 72} Pause {119 73} Pause {119 74} Pause {119 75} Pause {119 76} Break {119 77} Break {119 78} Break {119 79} Break {119 80} Pause {119 81} Pause {119 82} Pause {119 83} Pause {119 84} Break {119 85} Break {119 86} Break {119 87} Break {119 88} Pause {119 89} Pause {119 90} Pause {119 91} Pause {119 92} Break {119 93} Break {119 94} Break {119 95} Break {119 96} Pause {119 97} Pause {119 98} Pause {119 99} Pause {119 100} Break {119 101} Break {119 102} Break {119 103} Break {119 104} Pause {119 105} Pause {119 106} Pause {119 107} Pause {119 108} Break {119 109} Break {119 110} Break {119 111} Break {119 112} Pause {119 113} Pause {119 114} Pause {119 115} Pause {119 116} Break {119 117} Break {119 118} Break {119 119} Break {119 120} Pause {119 121} Pause {119 122} Pause {119 123} Pause {119 124} Break {119 125} Break {119 126} Break {119 127} Break {121 0} KP_Period {121 1} KP_Period {121 2} KP_Period {121 3} KP_Period {121 4} KP_Period {121 5} KP_Period {121 6} KP_Period {121 7} KP_Period {121 8} KP_Period {121 9} KP_Period {121 10} KP_Period {121 11} KP_Period {121 12} KP_Period {121 13} KP_Period {121 14} KP_Period {121 15} KP_Period {121 16} KP_Period {121 17} KP_Period {121 18} KP_Period {121 19} KP_Period {121 20} KP_Period {121 21} KP_Period {121 22} KP_Period {121 23} KP_Period {121 24} KP_Period {121 25} KP_Period {121 26} KP_Period {121 27} KP_Period {121 28} KP_Period {121 29} KP_Period {121 30} KP_Period {121 31} KP_Period {121 32} KP_Period {121 33} KP_Period {121 34} KP_Period {121 35} KP_Period {121 36} KP_Period {121 37} KP_Period {121 38} KP_Period {121 39} KP_Period {121 40} KP_Period {121 41} KP_Period {121 42} KP_Period {121 43} KP_Period {121 44} KP_Period {121 45} KP_Period {121 46} KP_Period {121 47} KP_Period {121 48} KP_Period {121 49} KP_Period {121 50} KP_Period {121 51} KP_Period {121 52} KP_Period {121 53} KP_Period {121 54} KP_Period {121 55} KP_Period {121 56} KP_Period {121 57} KP_Period {121 58} KP_Period {121 59} KP_Period {121 60} KP_Period {121 61} KP_Period {121 62} KP_Period {121 63} KP_Period {121 64} KP_Period {121 65} KP_Period {121 66} KP_Period {121 67} KP_Period {121 68} KP_Period {121 69} KP_Period {121 70} KP_Period {121 71} KP_Period {121 72} KP_Period {121 73} KP_Period {121 74} KP_Period {121 75} KP_Period {121 76} KP_Period {121 77} KP_Period {121 78} KP_Period {121 79} KP_Period {121 80} KP_Period {121 81} KP_Period {121 82} KP_Period {121 83} KP_Period {121 84} KP_Period {121 85} KP_Period {121 86} KP_Period {121 87} KP_Period {121 88} KP_Period {121 89} KP_Period {121 90} KP_Period {121 91} KP_Period {121 92} KP_Period {121 93} KP_Period {121 94} KP_Period {121 95} KP_Period {121 96} KP_Period {121 97} KP_Period {121 98} KP_Period {121 99} KP_Period {121 100} KP_Period {121 101} KP_Period {121 102} KP_Period {121 103} KP_Period {121 104} KP_Period {121 105} KP_Period {121 106} KP_Period {121 107} KP_Period {121 108} KP_Period {121 109} KP_Period {121 110} KP_Period {121 111} KP_Period {121 112} KP_Period {121 113} KP_Period {121 114} KP_Period {121 115} KP_Period {121 116} KP_Period {121 117} KP_Period {121 118} KP_Period {121 119} KP_Period {121 120} KP_Period {121 121} KP_Period {121 122} KP_Period {121 123} KP_Period {121 124} KP_Period {121 125} KP_Period {121 126} KP_Period {121 127} KP_Period {125 0} Alt {125 1} Alt {125 2} Alt {125 3} Alt {125 4} Alt {125 5} Alt {125 6} Alt {125 7} Alt {125 8} Alt {125 9} Alt {125 10} Alt {125 11} Alt {125 12} Alt {125 13} Alt {125 14} Alt {125 15} Alt {125 16} Alt {125 17} Alt {125 18} Alt {125 19} Alt {125 20} Alt {125 21} Alt {125 22} Alt {125 23} Alt {125 24} Alt {125 25} Alt {125 26} Alt {125 27} Alt {125 28} Alt {125 29} Alt {125 30} Alt {125 31} Alt {125 32} Alt {125 33} Alt {125 34} Alt {125 35} Alt {125 36} Alt {125 37} Alt {125 38} Alt {125 39} Alt {125 40} Alt {125 41} Alt {125 42} Alt {125 43} Alt {125 44} Alt {125 45} Alt {125 46} Alt {125 47} Alt {125 48} Alt {125 49} Alt {125 50} Alt {125 51} Alt {125 52} Alt {125 53} Alt {125 54} Alt {125 55} Alt {125 56} Alt {125 57} Alt {125 58} Alt {125 59} Alt {125 60} Alt {125 61} Alt {125 62} Alt {125 63} Alt {125 64} Alt {125 65} Alt {125 66} Alt {125 67} Alt {125 68} Alt {125 69} Alt {125 70} Alt {125 71} Alt {125 72} Alt {125 73} Alt {125 74} Alt {125 75} Alt {125 76} Alt {125 77} Alt {125 78} Alt {125 79} Alt {125 80} Alt {125 81} Alt {125 82} Alt {125 83} Alt {125 84} Alt {125 85} Alt {125 86} Alt {125 87} Alt {125 88} Alt {125 89} Alt {125 90} Alt {125 91} Alt {125 92} Alt {125 93} Alt {125 94} Alt {125 95} Alt {125 96} Alt {125 97} Alt {125 98} Alt {125 99} Alt {125 100} Alt {125 101} Alt {125 102} Alt {125 103} Alt {125 104} Alt {125 105} Alt {125 106} Alt {125 107} Alt {125 108} Alt {125 109} Alt {125 110} Alt {125 111} Alt {125 112} Alt {125 113} Alt {125 114} Alt {125 115} Alt {125 116} Alt {125 117} Alt {125 118} Alt {125 119} Alt {125 120} Alt {125 121} Alt {125 122} Alt {125 123} Alt {125 124} Alt {125 125} Alt {125 126} Alt {125 127} Alt {126 0} Alt {126 1} Alt {126 2} Alt {126 3} Alt {126 4} Alt {126 5} Alt {126 6} Alt {126 7} Alt {126 8} Alt {126 9} Alt {126 10} Alt {126 11} Alt {126 12} Alt {126 13} Alt {126 14} Alt {126 15} Alt {126 16} Alt {126 17} Alt {126 18} Alt {126 19} Alt {126 20} Alt {126 21} Alt {126 22} Alt {126 23} Alt {126 24} Alt {126 25} Alt {126 26} Alt {126 27} Alt {126 28} Alt {126 29} Alt {126 30} Alt {126 31} Alt {126 32} Alt {126 33} Alt {126 34} Alt {126 35} Alt {126 36} Alt {126 37} Alt {126 38} Alt {126 39} Alt {126 40} Alt {126 41} Alt {126 42} Alt {126 43} Alt {126 44} Alt {126 45} Alt {126 46} Alt {126 47} Alt {126 48} Alt {126 49} Alt {126 50} Alt {126 51} Alt {126 52} Alt {126 53} Alt {126 54} Alt {126 55} Alt {126 56} Alt {126 57} Alt {126 58} Alt {126 59} Alt {126 60} Alt {126 61} Alt {126 62} Alt {126 63} Alt {126 64} Alt {126 65} Alt {126 66} Alt {126 67} Alt {126 68} Alt {126 69} Alt {126 70} Alt {126 71} Alt {126 72} Alt {126 73} Alt {126 74} Alt {126 75} Alt {126 76} Alt {126 77} Alt {126 78} Alt {126 79} Alt {126 80} Alt {126 81} Alt {126 82} Alt {126 83} Alt {126 84} Alt {126 85} Alt {126 86} Alt {126 87} Alt {126 88} Alt {126 89} Alt {126 90} Alt {126 91} Alt {126 92} Alt {126 93} Alt {126 94} Alt {126 95} Alt {126 96} Alt {126 97} Alt {126 98} Alt {126 99} Alt {126 100} Alt {126 101} Alt {126 102} Alt {126 103} Alt {126 104} Alt {126 105} Alt {126 106} Alt {126 107} Alt {126 108} Alt {126 109} Alt {126 110} Alt {126 111} Alt {126 112} Alt {126 113} Alt {126 114} Alt {126 115} Alt {126 116} Alt {126 117} Alt {126 118} Alt {126 119} Alt {126 120} Alt {126 121} Alt {126 122} Alt {126 123} Alt {126 124} Alt {126 125} Alt {126 126} Alt {126 127} Alt} {{2 0} 1 {2 1} ! {2 2} 1 {2 3} ! {2 4} 1 {2 5} ! {2 6} 1 {2 7} ! {2 8} 1 {2 9} ! {2 10} 1 {2 11} ! {2 12} 1 {2 13} ! {2 14} 1 {2 15} ! {2 16} 1 {2 17} ! {2 18} 1 {2 19} ! {2 20} 1 {2 21} ! {2 22} 1 {2 23} ! {2 24} 1 {2 25} ! {2 26} 1 {2 27} ! {2 28} 1 {2 29} ! {2 30} 1 {2 31} ! {2 32} 1 {2 33} ! {2 34} 1 {2 35} ! {2 36} 1 {2 37} ! {2 38} 1 {2 39} ! {2 40} 1 {2 41} ! {2 42} 1 {2 43} ! {2 44} 1 {2 45} ! {2 46} 1 {2 47} ! {2 48} 1 {2 49} ! {2 50} 1 {2 51} ! {2 52} 1 {2 53} ! {2 54} 1 {2 55} ! {2 56} 1 {2 57} ! {2 58} 1 {2 59} ! {2 60} 1 {2 61} ! {2 62} 1 {2 63} ! {3 0} 2 {3 1} @ {3 2} 2 {3 3} @ {3 4} 2 {3 5} @ {3 6} 2 {3 7} @ {3 8} 2 {3 9} @ {3 10} 2 {3 11} @ {3 12} 2 {3 13} @ {3 14} 2 {3 15} @ {3 16} 2 {3 17} @ {3 18} 2 {3 19} @ {3 20} 2 {3 21} @ {3 22} 2 {3 23} @ {3 24} 2 {3 25} @ {3 26} 2 {3 27} @ {3 28} 2 {3 29} @ {3 30} 2 {3 31} @ {4 0} 3 {4 1} # {4 2} 3 {4 3} # {4 4} 3 {4 5} # {4 6} 3 {4 7} # {4 8} 3 {4 9} # {4 10} 3 {4 11} # {4 12} 3 {4 13} # {4 14} 3 {4 15} # {4 16} 3 {4 17} # {4 18} 3 {4 19} # {4 20} 3 {4 21} # {4 22} 3 {4 23} # {4 24} 3 {4 25} # {4 26} 3 {4 27} # {4 28} 3 {4 29} # {4 30} 3 {4 31} # {4 32} 3 {4 33} # {4 34} 3 {4 35} # {4 36} 3 {4 37} # {4 38} 3 {4 39} # {4 40} 3 {4 41} # {4 42} 3 {4 43} # {4 44} 3 {4 45} # {4 46} 3 {4 47} # {4 48} 3 {4 49} # {4 50} 3 {4 51} # {4 52} 3 {4 53} # {4 54} 3 {4 55} # {4 56} 3 {4 57} # {4 58} 3 {4 59} # {4 60} 3 {4 61} # {4 62} 3 {4 63} # {5 0} 4 {5 1} {$} {5 2} 4 {5 3} {$} {5 4} 4 {5 5} {$} {5 6} 4 {5 7} {$} {5 8} 4 {5 9} {$} {5 10} 4 {5 11} {$} {5 12} 4 {5 13} {$} {5 14} 4 {5 15} {$} {5 16} 4 {5 17} {$} {5 18} 4 {5 19} {$} {5 20} 4 {5 21} {$} {5 22} 4 {5 23} {$} {5 24} 4 {5 25} {$} {5 26} 4 {5 27} {$} {5 28} 4 {5 29} {$} {5 30} 4 {5 31} {$} {5 32} 4 {5 33} {$} {5 34} 4 {5 35} {$} {5 36} 4 {5 37} {$} {5 38} 4 {5 39} {$} {5 40} 4 {5 41} {$} {5 42} 4 {5 43} {$} {5 44} 4 {5 45} {$} {5 46} 4 {5 47} {$} {5 48} 4 {5 49} {$} {5 50} 4 {5 51} {$} {5 52} 4 {5 53} {$} {5 54} 4 {5 55} {$} {5 56} 4 {5 57} {$} {5 58} 4 {5 59} {$} {5 60} 4 {5 61} {$} {5 62} 4 {5 63} {$} {6 0} 5 {6 1} % {6 2} 5 {6 3} % {6 4} 5 {6 5} % {6 6} 5 {6 7} % {6 8} 5 {6 9} % {6 10} 5 {6 11} % {6 12} 5 {6 13} % {6 14} 5 {6 15} % {6 16} 5 {6 17} % {6 18} 5 {6 19} % {6 20} 5 {6 21} % {6 22} 5 {6 23} % {6 24} 5 {6 25} % {6 26} 5 {6 27} % {6 28} 5 {6 29} % {6 30} 5 {6 31} % {6 32} 5 {6 33} % {6 34} 5 {6 35} % {6 36} 5 {6 37} % {6 38} 5 {6 39} % {6 40} 5 {6 41} % {6 42} 5 {6 43} % {6 44} 5 {6 45} % {6 46} 5 {6 47} % {6 48} 5 {6 49} % {6 50} 5 {6 51} % {6 52} 5 {6 53} % {6 54} 5 {6 55} % {6 56} 5 {6 57} % {6 58} 5 {6 59} % {6 60} 5 {6 61} % {6 62} 5 {6 63} % {7 0} 6 {7 1} ^ {7 2} 6 {7 3} ^ {7 4} 6 {7 5} ^ {7 6} 6 {7 7} ^ {7 8} 6 {7 9} ^ {7 10} 6 {7 11} ^ {7 12} 6 {7 13} ^ {7 14} 6 {7 15} ^ {7 16} 6 {7 17} ^ {7 18} 6 {7 19} ^ {7 20} 6 {7 21} ^ {7 22} 6 {7 23} ^ {7 24} 6 {7 25} ^ {7 26} 6 {7 27} ^ {7 28} 6 {7 29} ^ {7 30} 6 {7 31} ^ {8 0} 7 {8 1} & {8 2} 7 {8 3} & {8 4} 7 {8 5} & {8 6} 7 {8 7} & {8 8} 7 {8 9} & {8 10} 7 {8 11} & {8 12} 7 {8 13} & {8 14} 7 {8 15} & {8 16} 7 {8 17} & {8 18} 7 {8 19} & {8 20} 7 {8 21} & {8 22} 7 {8 23} & {8 24} 7 {8 25} & {8 26} 7 {8 27} & {8 28} 7 {8 29} & {8 30} 7 {8 31} & {8 32} 7 {8 33} & {8 34} 7 {8 35} & {8 36} 7 {8 37} & {8 38} 7 {8 39} & {8 40} 7 {8 41} & {8 42} 7 {8 43} & {8 44} 7 {8 45} & {8 46} 7 {8 47} & {8 48} 7 {8 49} & {8 50} 7 {8 51} & {8 52} 7 {8 53} & {8 54} 7 {8 55} & {8 56} 7 {8 57} & {8 58} 7 {8 59} & {8 60} 7 {8 61} & {8 62} 7 {8 63} & {9 0} 8 {9 1} * {9 2} 8 {9 3} * {9 4} 8 {9 5} * {9 6} 8 {9 7} * {9 8} 8 {9 9} * {9 10} 8 {9 11} * {9 12} 8 {9 13} * {9 14} 8 {9 15} * {9 16} 8 {9 17} * {9 18} 8 {9 19} * {9 20} 8 {9 21} * {9 22} 8 {9 23} * {9 24} 8 {9 25} * {9 26} 8 {9 27} * {9 28} 8 {9 29} * {9 30} 8 {9 31} * {9 32} 8 {9 33} * {9 34} 8 {9 35} * {9 36} 8 {9 37} * {9 38} 8 {9 39} * {9 40} 8 {9 41} * {9 42} 8 {9 43} * {9 44} 8 {9 45} * {9 46} 8 {9 47} * {9 48} 8 {9 49} * {9 50} 8 {9 51} * {9 52} 8 {9 53} * {9 54} 8 {9 55} * {9 56} 8 {9 57} * {9 58} 8 {9 59} * {9 60} 8 {9 61} * {9 62} 8 {9 63} * {10 0} 9 {10 1} ( {10 2} 9 {10 3} ( {10 4} 9 {10 5} ( {10 6} 9 {10 7} ( {10 8} 9 {10 9} ( {10 10} 9 {10 11} ( {10 12} 9 {10 13} ( {10 14} 9 {10 15} ( {10 16} 9 {10 17} ( {10 18} 9 {10 19} ( {10 20} 9 {10 21} ( {10 22} 9 {10 23} ( {10 24} 9 {10 25} ( {10 26} 9 {10 27} ( {10 28} 9 {10 29} ( {10 30} 9 {10 31} ( {10 32} 9 {10 33} ( {10 34} 9 {10 35} ( {10 36} 9 {10 37} ( {10 38} 9 {10 39} ( {10 40} 9 {10 41} ( {10 42} 9 {10 43} ( {10 44} 9 {10 45} ( {10 46} 9 {10 47} ( {10 48} 9 {10 49} ( {10 50} 9 {10 51} ( {10 52} 9 {10 53} ( {10 54} 9 {10 55} ( {10 56} 9 {10 57} ( {10 58} 9 {10 59} ( {10 60} 9 {10 61} ( {10 62} 9 {10 63} ( {11 0} 0 {11 1} ) {11 2} 0 {11 3} ) {11 4} 0 {11 5} ) {11 6} 0 {11 7} ) {11 8} 0 {11 9} ) {11 10} 0 {11 11} ) {11 12} 0 {11 13} ) {11 14} 0 {11 15} ) {11 16} 0 {11 17} ) {11 18} 0 {11 19} ) {11 20} 0 {11 21} ) {11 22} 0 {11 23} ) {11 24} 0 {11 25} ) {11 26} 0 {11 27} ) {11 28} 0 {11 29} ) {11 30} 0 {11 31} ) {11 32} 0 {11 33} ) {11 34} 0 {11 35} ) {11 36} 0 {11 37} ) {11 38} 0 {11 39} ) {11 40} 0 {11 41} ) {11 42} 0 {11 43} ) {11 44} 0 {11 45} ) {11 46} 0 {11 47} ) {11 48} 0 {11 49} ) {11 50} 0 {11 51} ) {11 52} 0 {11 53} ) {11 54} 0 {11 55} ) {11 56} 0 {11 57} ) {11 58} 0 {11 59} ) {11 60} 0 {11 61} ) {11 62} 0 {11 63} ) {12 0} - {12 1} _ {12 2} - {12 3} _ {12 4} - {12 5} _ {12 6} - {12 7} _ {12 8} - {12 9} _ {12 10} - {12 11} _ {12 12} - {12 13} _ {12 14} - {12 15} _ {12 16} - {12 17} _ {12 18} - {12 19} _ {12 20} - {12 21} _ {12 22} - {12 23} _ {12 24} - {12 25} _ {12 26} - {12 27} _ {12 28} - {12 29} _ {12 30} - {12 31} _ {13 0} = {13 1} + {13 2} = {13 3} + {13 4} = {13 5} + {13 6} = {13 7} + {13 8} = {13 9} + {13 10} = {13 11} + {13 12} = {13 13} + {13 14} = {13 15} + {13 16} = {13 17} + {13 18} = {13 19} + {13 20} = {13 21} + {13 22} = {13 23} + {13 24} = {13 25} + {13 26} = {13 27} + {13 28} = {13 29} + {13 30} = {13 31} + {13 32} = {13 33} + {13 34} = {13 35} + {13 36} = {13 37} + {13 38} = {13 39} + {13 40} = {13 41} + {13 42} = {13 43} + {13 44} = {13 45} + {13 46} = {13 47} + {13 48} = {13 49} + {13 50} = {13 51} + {13 52} = {13 53} + {13 54} = {13 55} + {13 56} = {13 57} + {13 58} = {13 59} + {13 60} = {13 61} + {13 62} = {13 63} + {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} q {16 5} Q {16 6} q {16 7} Q {16 8} q {16 9} Q {16 10} q {16 11} Q {16 12} q {16 13} Q {16 14} q {16 15} Q {16 16} Q {16 17} q {16 18} Q {16 19} q {16 20} Q {16 21} q {16 22} Q {16 23} q {16 24} Q {16 25} q {16 26} Q {16 27} q {16 28} Q {16 29} q {16 30} Q {16 31} q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} w {17 5} W {17 6} w {17 7} W {17 8} w {17 9} W {17 10} w {17 11} W {17 12} w {17 13} W {17 14} w {17 15} W {17 16} W {17 17} w {17 18} W {17 19} w {17 20} W {17 21} w {17 22} W {17 23} w {17 24} W {17 25} w {17 26} W {17 27} w {17 28} W {17 29} w {17 30} W {17 31} w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} e {18 5} E {18 6} e {18 7} E {18 8} e {18 9} E {18 10} e {18 11} E {18 12} e {18 13} E {18 14} e {18 15} E {18 16} E {18 17} e {18 18} E {18 19} e {18 20} E {18 21} e {18 22} E {18 23} e {18 24} E {18 25} e {18 26} E {18 27} e {18 28} E {18 29} e {18 30} E {18 31} e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} r {19 5} R {19 6} r {19 7} R {19 8} r {19 9} R {19 10} r {19 11} R {19 12} r {19 13} R {19 14} r {19 15} R {19 16} R {19 17} r {19 18} R {19 19} r {19 20} R {19 21} r {19 22} R {19 23} r {19 24} R {19 25} r {19 26} R {19 27} r {19 28} R {19 29} r {19 30} R {19 31} r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} t {20 5} T {20 6} t {20 7} T {20 8} t {20 9} T {20 10} t {20 11} T {20 12} t {20 13} T {20 14} t {20 15} T {20 16} T {20 17} t {20 18} T {20 19} t {20 20} T {20 21} t {20 22} T {20 23} t {20 24} T {20 25} t {20 26} T {20 27} t {20 28} T {20 29} t {20 30} T {20 31} t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} y {21 5} Y {21 6} y {21 7} Y {21 8} y {21 9} Y {21 10} y {21 11} Y {21 12} y {21 13} Y {21 14} y {21 15} Y {21 16} Y {21 17} y {21 18} Y {21 19} y {21 20} Y {21 21} y {21 22} Y {21 23} y {21 24} Y {21 25} y {21 26} Y {21 27} y {21 28} Y {21 29} y {21 30} Y {21 31} y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} u {22 5} U {22 6} u {22 7} U {22 8} u {22 9} U {22 10} u {22 11} U {22 12} u {22 13} U {22 14} u {22 15} U {22 16} U {22 17} u {22 18} U {22 19} u {22 20} U {22 21} u {22 22} U {22 23} u {22 24} U {22 25} u {22 26} U {22 27} u {22 28} U {22 29} u {22 30} U {22 31} u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} i {23 5} I {23 6} i {23 7} I {23 8} i {23 9} I {23 10} i {23 11} I {23 12} i {23 13} I {23 14} i {23 15} I {23 16} I {23 17} i {23 18} I {23 19} i {23 20} I {23 21} i {23 22} I {23 23} i {23 24} I {23 25} i {23 26} I {23 27} i {23 28} I {23 29} i {23 30} I {23 31} i {24 0} o {24 1} O {24 2} o {24 3} O {24 4} o {24 5} O {24 6} o {24 7} O {24 8} o {24 9} O {24 10} o {24 11} O {24 12} o {24 13} O {24 14} o {24 15} O {24 16} O {24 17} o {24 18} O {24 19} o {24 20} O {24 21} o {24 22} O {24 23} o {24 24} O {24 25} o {24 26} O {24 27} o {24 28} O {24 29} o {24 30} O {24 31} o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} p {25 5} P {25 6} p {25 7} P {25 8} p {25 9} P {25 10} p {25 11} P {25 12} p {25 13} P {25 14} p {25 15} P {25 16} P {25 17} p {25 18} P {25 19} p {25 20} P {25 21} p {25 22} P {25 23} p {25 24} P {25 25} p {25 26} P {25 27} p {25 28} P {25 29} p {25 30} P {25 31} p {26 0} {[} {26 1} \{ {26 2} {[} {26 3} \{ {26 4} {[} {26 5} \{ {26 6} {[} {26 7} \{ {26 8} {[} {26 9} \{ {26 10} {[} {26 11} \{ {26 12} {[} {26 13} \{ {26 14} {[} {26 15} \{ {26 16} {[} {26 17} \{ {26 18} {[} {26 19} \{ {26 20} {[} {26 21} \{ {26 22} {[} {26 23} \{ {26 24} {[} {26 25} \{ {26 26} {[} {26 27} \{ {26 28} {[} {26 29} \{ {26 30} {[} {26 31} \{ {27 0} \] {27 1} \} {27 2} \] {27 3} \} {27 4} \] {27 5} \} {27 6} \] {27 7} \} {27 8} \] {27 9} \} {27 10} \] {27 11} \} {27 12} \] {27 13} \} {27 14} \] {27 15} \} {27 16} \] {27 17} \} {27 18} \] {27 19} \} {27 20} \] {27 21} \} {27 22} \] {27 23} \} {27 24} \] {27 25} \} {27 26} \] {27 27} \} {27 28} \] {27 29} \} {27 30} \] {27 31} \} {30 0} a {30 1} A {30 2} a {30 3} A {30 4} a {30 5} A {30 6} a {30 7} A {30 8} a {30 9} A {30 10} a {30 11} A {30 12} a {30 13} A {30 14} a {30 15} A {30 16} A {30 17} a {30 18} A {30 19} a {30 20} A {30 21} a {30 22} A {30 23} a {30 24} A {30 25} a {30 26} A {30 27} a {30 28} A {30 29} a {30 30} A {30 31} a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} s {31 5} S {31 6} s {31 7} S {31 8} s {31 9} S {31 10} s {31 11} S {31 12} s {31 13} S {31 14} s {31 15} S {31 16} S {31 17} s {31 18} S {31 19} s {31 20} S {31 21} s {31 22} S {31 23} s {31 24} S {31 25} s {31 26} S {31 27} s {31 28} S {31 29} s {31 30} S {31 31} s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} d {32 5} D {32 6} d {32 7} D {32 8} d {32 9} D {32 10} d {32 11} D {32 12} d {32 13} D {32 14} d {32 15} D {32 16} D {32 17} d {32 18} D {32 19} d {32 20} D {32 21} d {32 22} D {32 23} d {32 24} D {32 25} d {32 26} D {32 27} d {32 28} D {32 29} d {32 30} D {32 31} d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} f {33 5} F {33 6} f {33 7} F {33 8} f {33 9} F {33 10} f {33 11} F {33 12} f {33 13} F {33 14} f {33 15} F {33 16} F {33 17} f {33 18} F {33 19} f {33 20} F {33 21} f {33 22} F {33 23} f {33 24} F {33 25} f {33 26} F {33 27} f {33 28} F {33 29} f {33 30} F {33 31} f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} g {34 5} G {34 6} g {34 7} G {34 8} g {34 9} G {34 10} g {34 11} G {34 12} g {34 13} G {34 14} g {34 15} G {34 16} G {34 17} g {34 18} G {34 19} g {34 20} G {34 21} g {34 22} G {34 23} g {34 24} G {34 25} g {34 26} G {34 27} g {34 28} G {34 29} g {34 30} G {34 31} g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} h {35 5} H {35 6} h {35 7} H {35 8} h {35 9} H {35 10} h {35 11} H {35 12} h {35 13} H {35 14} h {35 15} H {35 16} H {35 17} h {35 18} H {35 19} h {35 20} H {35 21} h {35 22} H {35 23} h {35 24} H {35 25} h {35 26} H {35 27} h {35 28} H {35 29} h {35 30} H {35 31} h {36 0} j {36 1} J {36 2} j {36 3} J {36 4} j {36 5} J {36 6} j {36 7} J {36 8} j {36 9} J {36 10} j {36 11} J {36 12} j {36 13} J {36 14} j {36 15} J {36 16} J {36 17} j {36 18} J {36 19} j {36 20} J {36 21} j {36 22} J {36 23} j {36 24} J {36 25} j {36 26} J {36 27} j {36 28} J {36 29} j {36 30} J {36 31} j {37 0} k {37 1} K {37 2} k {37 3} K {37 4} k {37 5} K {37 6} k {37 7} K {37 8} k {37 9} K {37 10} k {37 11} K {37 12} k {37 13} K {37 14} k {37 15} K {37 16} K {37 17} k {37 18} K {37 19} k {37 20} K {37 21} k {37 22} K {37 23} k {37 24} K {37 25} k {37 26} K {37 27} k {37 28} K {37 29} k {37 30} K {37 31} k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} l {38 5} L {38 6} l {38 7} L {38 8} l {38 9} L {38 10} l {38 11} L {38 12} l {38 13} L {38 14} l {38 15} L {38 16} L {38 17} l {38 18} L {38 19} l {38 20} L {38 21} l {38 22} L {38 23} l {38 24} L {38 25} l {38 26} L {38 27} l {38 28} L {38 29} l {38 30} L {38 31} l {39 0} {;} {39 1} : {39 2} {;} {39 3} : {39 4} {;} {39 5} : {39 6} {;} {39 7} : {39 8} {;} {39 9} : {39 10} {;} {39 11} : {39 12} {;} {39 13} : {39 14} {;} {39 15} : {39 16} {;} {39 17} : {39 18} {;} {39 19} : {39 20} {;} {39 21} : {39 22} {;} {39 23} : {39 24} {;} {39 25} : {39 26} {;} {39 27} : {39 28} {;} {39 29} : {39 30} {;} {39 31} : {39 32} {;} {39 33} : {39 34} {;} {39 35} : {39 36} {;} {39 37} : {39 38} {;} {39 39} : {39 40} {;} {39 41} : {39 42} {;} {39 43} : {39 44} {;} {39 45} : {39 46} {;} {39 47} : {39 48} {;} {39 49} : {39 50} {;} {39 51} : {39 52} {;} {39 53} : {39 54} {;} {39 55} : {39 56} {;} {39 57} : {39 58} {;} {39 59} : {39 60} {;} {39 61} : {39 62} {;} {39 63} : {40 0} ' {40 1} {"} {40 2} ' {40 3} {"} {40 4} ' {40 5} {"} {40 6} ' {40 7} {"} {40 8} ' {40 9} {"} {40 10} ' {40 11} {"} {40 12} ' {40 13} {"} {40 14} ' {40 15} {"} {40 16} ' {40 17} {"} {40 18} ' {40 19} {"} {40 20} ' {40 21} {"} {40 22} ' {40 23} {"} {40 24} ' {40 25} {"} {40 26} ' {40 27} {"} {40 28} ' {40 29} {"} {40 30} ' {40 31} {"} {40 32} ' {40 33} {"} {40 34} ' {40 35} {"} {40 36} ' {40 37} {"} {40 38} ' {40 39} {"} {40 40} ' {40 41} {"} {40 42} ' {40 43} {"} {40 44} ' {40 45} {"} {40 46} ' {40 47} {"} {40 48} ' {40 49} {"} {40 50} ' {40 51} {"} {40 52} ' {40 53} {"} {40 54} ' {40 55} {"} {40 56} ' {40 57} {"} {40 58} ' {40 59} {"} {40 60} ' {40 61} {"} {40 62} ' {40 63} {"} {41 0} ` {41 1} ~ {41 2} ` {41 3} ~ {41 4} ` {41 5} ~ {41 6} ` {41 7} ~ {41 8} ` {41 9} ~ {41 10} ` {41 11} ~ {41 12} ` {41 13} ~ {41 14} ` {41 15} ~ {41 16} ` {41 17} ~ {41 18} ` {41 19} ~ {41 20} ` {41 21} ~ {41 22} ` {41 23} ~ {41 24} ` {41 25} ~ {41 26} ` {41 27} ~ {41 28} ` {41 29} ~ {41 30} ` {41 31} ~ {43 0} \\ {43 1} | {43 2} \\ {43 3} | {43 4} \\ {43 5} | {43 6} \\ {43 7} | {43 8} \\ {43 9} | {43 10} \\ {43 11} | {43 12} \\ {43 13} | {43 14} \\ {43 15} | {43 16} \\ {43 17} | {43 18} \\ {43 19} | {43 20} \\ {43 21} | {43 22} \\ {43 23} | {43 24} \\ {43 25} | {43 26} \\ {43 27} | {43 28} \\ {43 29} | {43 30} \\ {43 31} | {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} z {44 5} Z {44 6} z {44 7} Z {44 8} z {44 9} Z {44 10} z {44 11} Z {44 12} z {44 13} Z {44 14} z {44 15} Z {44 16} Z {44 17} z {44 18} Z {44 19} z {44 20} Z {44 21} z {44 22} Z {44 23} z {44 24} Z {44 25} z {44 26} Z {44 27} z {44 28} Z {44 29} z {44 30} Z {44 31} z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} x {45 5} X {45 6} x {45 7} X {45 8} x {45 9} X {45 10} x {45 11} X {45 12} x {45 13} X {45 14} x {45 15} X {45 16} X {45 17} x {45 18} X {45 19} x {45 20} X {45 21} x {45 22} X {45 23} x {45 24} X {45 25} x {45 26} X {45 27} x {45 28} X {45 29} x {45 30} X {45 31} x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} c {46 5} C {46 6} c {46 7} C {46 8} c {46 9} C {46 10} c {46 11} C {46 12} c {46 13} C {46 14} c {46 15} C {46 16} C {46 17} c {46 18} C {46 19} c {46 20} C {46 21} c {46 22} C {46 23} c {46 24} C {46 25} c {46 26} C {46 27} c {46 28} C {46 29} c {46 30} C {46 31} c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} v {47 5} V {47 6} v {47 7} V {47 8} v {47 9} V {47 10} v {47 11} V {47 12} v {47 13} V {47 14} v {47 15} V {47 16} V {47 17} v {47 18} V {47 19} v {47 20} V {47 21} v {47 22} V {47 23} v {47 24} V {47 25} v {47 26} V {47 27} v {47 28} V {47 29} v {47 30} V {47 31} v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} b {48 5} B {48 6} b {48 7} B {48 8} b {48 9} B {48 10} b {48 11} B {48 12} b {48 13} B {48 14} b {48 15} B {48 16} B {48 17} b {48 18} B {48 19} b {48 20} B {48 21} b {48 22} B {48 23} b {48 24} B {48 25} b {48 26} B {48 27} b {48 28} B {48 29} b {48 30} B {48 31} b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} n {49 5} N {49 6} n {49 7} N {49 8} n {49 9} N {49 10} n {49 11} N {49 12} n {49 13} N {49 14} n {49 15} N {49 16} N {49 17} n {49 18} N {49 19} n {49 20} N {49 21} n {49 22} N {49 23} n {49 24} N {49 25} n {49 26} N {49 27} n {49 28} N {49 29} n {49 30} N {49 31} n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} m {50 5} M {50 6} m {50 7} M {50 8} m {50 9} M {50 10} m {50 11} M {50 12} m {50 13} M {50 14} m {50 15} M {50 16} M {50 17} m {50 18} M {50 19} m {50 20} M {50 21} m {50 22} M {50 23} m {50 24} M {50 25} m {50 26} M {50 27} m {50 28} M {50 29} m {50 30} M {50 31} m {51 0} , {51 1} < {51 2} , {51 3} < {51 4} , {51 5} < {51 6} , {51 7} < {51 8} , {51 9} < {51 10} , {51 11} < {51 12} , {51 13} < {51 14} , {51 15} < {51 16} , {51 17} < {51 18} , {51 19} < {51 20} , {51 21} < {51 22} , {51 23} < {51 24} , {51 25} < {51 26} , {51 27} < {51 28} , {51 29} < {51 30} , {51 31} < {51 32} , {51 33} < {51 34} , {51 35} < {51 36} , {51 37} < {51 38} , {51 39} < {51 40} , {51 41} < {51 42} , {51 43} < {51 44} , {51 45} < {51 46} , {51 47} < {51 48} , {51 49} < {51 50} , {51 51} < {51 52} , {51 53} < {51 54} , {51 55} < {51 56} , {51 57} < {51 58} , {51 59} < {51 60} , {51 61} < {51 62} , {51 63} < {52 0} . {52 1} > {52 2} . {52 3} > {52 4} . {52 5} > {52 6} . {52 7} > {52 8} . {52 9} > {52 10} . {52 11} > {52 12} . {52 13} > {52 14} . {52 15} > {52 16} . {52 17} > {52 18} . {52 19} > {52 20} . {52 21} > {52 22} . {52 23} > {52 24} . {52 25} > {52 26} . {52 27} > {52 28} . {52 29} > {52 30} . {52 31} > {53 0} / {53 1} ? {53 2} / {53 3} ? {53 4} / {53 5} ? {53 6} / {53 7} ? {53 8} / {53 9} ? {53 10} / {53 11} ? {53 12} / {53 13} ? {53 14} / {53 15} ? {53 16} / {53 17} ? {53 18} / {53 19} ? {53 20} / {53 21} ? {53 22} / {53 23} ? {53 24} / {53 25} ? {53 26} / {53 27} ? {53 28} / {53 29} ? {53 30} / {53 31} ? {57 0} { } {57 1} { } {57 2} { } {57 3} { } {57 4} { } {57 5} { } {57 6} { } {57 7} { } {57 8} { } {57 9} { } {57 10} { } {57 11} { } {57 12} { } {57 13} { } {57 14} { } {57 15} { } {57 16} { } {57 17} { } {57 18} { } {57 19} { } {57 20} { } {57 21} { } {57 22} { } {57 23} { } {57 24} { } {57 25} { } {57 26} { } {57 27} { } {57 28} { } {57 29} { } {57 30} { } {57 31} { } {86 0} < {86 1} > {86 2} | {86 3} ¦ {86 4} > {86 5} < {86 6} > {86 7} | {86 8} ¦ {86 9} > {86 10} < {86 11} > {86 12} | {86 13} ¦ {86 14} > {86 15} < {86 16} > {86 17} | {86 18} ¦ {86 19} > {86 20} < {86 21} > {86 22} | {86 23} ¦ {86 24} > {86 25} < {86 26} > {86 27} | {86 28} ¦ {86 29} > {86 30} < {86 31} > {86 32} | {86 33} ¦ {86 34} > {86 35} < {86 36} > {86 37} | {86 38} ¦ {86 39} >}} keyboardFileno 227 grabber <C:cfileUWOMQ5> cc ::<reference.<C______>.00000000000000000002>}}
when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd local ()when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd locale /locale/ \n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd} {keyboardChannel ::aio.handle10 KEY_STATES {up down repeat} defaultKeymap {{{1 0} Escape {1 1} Escape {1 2} Escape {1 3} Escape {1 4} Escape {1 5} Escape {1 6} Escape {1 7} Escape {1 8} Meta_Escape {1 9} Meta_Escape {1 10} Meta_Escape {1 11} Meta_Escape {1 12} Meta_Escape {1 13} Meta_Escape {1 14} Meta_Escape {1 15} Meta_Escape {1 16} Escape {1 17} Escape {1 18} Escape {1 19} Escape {1 20} Escape {1 21} Escape {1 22} Escape {1 23} Escape {1 24} Meta_Escape {1 25} Meta_Escape {1 26} Meta_Escape {1 27} Meta_Escape {1 28} Meta_Escape {1 29} Meta_Escape {1 30} Meta_Escape {1 31} Meta_Escape {1 32} Escape {1 33} Escape {1 34} Escape {1 35} Escape {1 36} Escape {1 37} Escape {1 38} Escape {1 39} Escape {1 40} Meta_Escape {1 41} Meta_Escape {1 42} Meta_Escape {1 43} Meta_Escape {1 44} Meta_Escape {1 45} Meta_Escape {1 46} Meta_Escape {1 47} Meta_Escape {1 48} Escape {1 49} Escape {1 50} Escape {1 51} Escape {1 52} Escape {1 53} Escape {1 54} Escape {1 55} Escape {1 56} Meta_Escape {1 57} Meta_Escape {1 58} Meta_Escape {1 59} Meta_Escape {1 60} Meta_Escape {1 61} Meta_Escape {1 62} Meta_Escape {1 63} Meta_Escape {1 64} Escape {1 65} Escape {1 66} Escape {1 67} Escape {1 68} Escape {1 69} Escape {1 70} Escape {1 71} Escape {1 72} Meta_Escape {1 73} Meta_Escape {1 74} Meta_Escape {1 75} Meta_Escape {1 76} Meta_Escape {1 77} Meta_Escape {1 78} Meta_Escape {1 79} Meta_Escape {1 80} Escape {1 81} Escape {1 82} Escape {1 83} Escape {1 84} Escape {1 85} Escape {1 86} Escape {1 87} Escape {1 88} Meta_Escape {1 89} Meta_Escape {1 90} Meta_Escape {1 91} Meta_Escape {1 92} Meta_Escape {1 93} Meta_Escape {1 94} Meta_Escape {1 95} Meta_Escape {1 96} Escape {1 97} Escape {1 98} Escape {1 99} Escape {1 100} Escape {1 101} Escape {1 102} Escape {1 103} Escape {1 104} Meta_Escape {1 105} Meta_Escape {1 106} Meta_Escape {1 107} Meta_Escape {1 108} Meta_Escape {1 109} Meta_Escape {1 110} Meta_Escape {1 111} Meta_Escape {1 112} Escape {1 113} Escape {1 114} Escape {1 115} Escape {1 116} Escape {1 117} Escape {1 118} Escape {1 119} Escape {1 120} Meta_Escape {1 121} Meta_Escape {1 122} Meta_Escape {1 123} Meta_Escape {1 124} Meta_Escape {1 125} Meta_Escape {1 126} Meta_Escape {1 127} Meta_Escape {2 0} one {2 1} exclam {2 2} one {2 3} exclam {2 4} one {2 5} exclam {2 6} one {2 7} exclam {2 8} Meta_one {2 9} Meta_exclam {2 10} Meta_one {2 11} Meta_exclam {2 12} Meta_one {2 13} Meta_exclam {2 14} Meta_one {2 15} Meta_exclam {2 16} one {2 17} exclam {2 18} one {2 19} exclam {2 20} one {2 21} exclam {2 22} one {2 23} exclam {2 24} Meta_one {2 25} Meta_exclam {2 26} Meta_one {2 27} Meta_exclam {2 28} Meta_one {2 29} Meta_exclam {2 30} Meta_one {2 31} Meta_exclam {2 32} one {2 33} exclam {2 34} one {2 35} exclam {2 36} one {2 37} exclam {2 38} one {2 39} exclam {2 40} Meta_one {2 41} Meta_exclam {2 42} Meta_one {2 43} Meta_exclam {2 44} Meta_one {2 45} Meta_exclam {2 46} Meta_one {2 47} Meta_exclam {2 48} one {2 49} exclam {2 50} one {2 51} exclam {2 52} one {2 53} exclam {2 54} one {2 55} exclam {2 56} Meta_one {2 57} Meta_exclam {2 58} Meta_one {2 59} Meta_exclam {2 60} Meta_one {2 61} Meta_exclam {2 62} Meta_one {2 63} Meta_exclam {2 64} one {2 65} exclam {2 66} one {2 67} exclam {2 68} one {2 69} exclam {2 70} one {2 71} exclam {2 72} Meta_one {2 73} Meta_exclam {2 74} Meta_one {2 75} Meta_exclam {2 76} Meta_one {2 77} Meta_exclam {2 78} Meta_one {2 79} Meta_exclam {2 80} one {2 81} exclam {2 82} one {2 83} exclam {2 84} one {2 85} exclam {2 86} one {2 87} exclam {2 88} Meta_one {2 89} Meta_exclam {2 90} Meta_one {2 91} Meta_exclam {2 92} Meta_one {2 93} Meta_exclam {2 94} Meta_one {2 95} Meta_exclam {2 96} one {2 97} exclam {2 98} one {2 99} exclam {2 100} one {2 101} exclam {2 102} one {2 103} exclam {2 104} Meta_one {2 105} Meta_exclam {2 106} Meta_one {2 107} Meta_exclam {2 108} Meta_one {2 109} Meta_exclam {2 110} Meta_one {2 111} Meta_exclam {2 112} one {2 113} exclam {2 114} one {2 115} exclam {2 116} one {2 117} exclam {2 118} one {2 119} exclam {2 120} Meta_one {2 121} Meta_exclam {2 122} Meta_one {2 123} Meta_exclam {2 124} Meta_one {2 125} Meta_exclam {2 126} Meta_one {2 127} Meta_exclam {3 0} two {3 1} at {3 2} two {3 3} at {3 4} nul {3 5} nul {3 6} nul {3 7} nul {3 8} Meta_two {3 9} Meta_at {3 10} Meta_two {3 11} Meta_at {3 12} Meta_nul {3 13} Meta_nul {3 14} Meta_nul {3 15} Meta_nul {3 16} two {3 17} at {3 18} two {3 19} at {3 20} nul {3 21} nul {3 22} nul {3 23} nul {3 24} Meta_two {3 25} Meta_at {3 26} Meta_two {3 27} Meta_at {3 28} Meta_nul {3 29} Meta_nul {3 30} Meta_nul {3 31} Meta_nul {3 32} two {3 33} at {3 34} two {3 35} at {3 36} nul {3 37} nul {3 38} nul {3 39} nul {3 40} Meta_two {3 41} Meta_at {3 42} Meta_two {3 43} Meta_at {3 44} Meta_nul {3 45} Meta_nul {3 46} Meta_nul {3 47} Meta_nul {3 48} two {3 49} at {3 50} two {3 51} at {3 52} nul {3 53} nul {3 54} nul {3 55} nul {3 56} Meta_two {3 57} Meta_at {3 58} Meta_two {3 59} Meta_at {3 60} Meta_nul {3 61} Meta_nul {3 62} Meta_nul {3 63} Meta_nul {3 64} two {3 65} at {3 66} two {3 67} at {3 68} nul {3 69} nul {3 70} nul {3 71} nul {3 72} Meta_two {3 73} Meta_at {3 74} Meta_two {3 75} Meta_at {3 76} Meta_nul {3 77} Meta_nul {3 78} Meta_nul {3 79} Meta_nul {3 80} two {3 81} at {3 82} two {3 83} at {3 84} nul {3 85} nul {3 86} nul {3 87} nul {3 88} Meta_two {3 89} Meta_at {3 90} Meta_two {3 91} Meta_at {3 92} Meta_nul {3 93} Meta_nul {3 94} Meta_nul {3 95} Meta_nul {3 96} two {3 97} at {3 98} two {3 99} at {3 100} nul {3 101} nul {3 102} nul {3 103} nul {3 104} Meta_two {3 105} Meta_at {3 106} Meta_two {3 107} Meta_at {3 108} Meta_nul {3 109} Meta_nul {3 110} Meta_nul {3 111} Meta_nul {3 112} two {3 113} at {3 114} two {3 115} at {3 116} nul {3 117} nul {3 118} nul {3 119} nul {3 120} Meta_two {3 121} Meta_at {3 122} Meta_two {3 123} Meta_at {3 124} Meta_nul {3 125} Meta_nul {3 126} Meta_nul {3 127} Meta_nul {4 0} three {4 1} numbersign {4 2} three {4 3} numbersign {4 4} three {4 5} numbersign {4 6} three {4 7} numbersign {4 8} Meta_three {4 9} Meta_numbersign {4 10} Meta_three {4 11} Meta_numbersign {4 12} Meta_three {4 13} Meta_numbersign {4 14} Meta_three {4 15} Meta_numbersign {4 16} three {4 17} numbersign {4 18} three {4 19} numbersign {4 20} three {4 21} numbersign {4 22} three {4 23} numbersign {4 24} Meta_three {4 25} Meta_numbersign {4 26} Meta_three {4 27} Meta_numbersign {4 28} Meta_three {4 29} Meta_numbersign {4 30} Meta_three {4 31} Meta_numbersign {4 32} three {4 33} numbersign {4 34} three {4 35} numbersign {4 36} three {4 37} numbersign {4 38} three {4 39} numbersign {4 40} Meta_three {4 41} Meta_numbersign {4 42} Meta_three {4 43} Meta_numbersign {4 44} Meta_three {4 45} Meta_numbersign {4 46} Meta_three {4 47} Meta_numbersign {4 48} three {4 49} numbersign {4 50} three {4 51} numbersign {4 52} three {4 53} numbersign {4 54} three {4 55} numbersign {4 56} Meta_three {4 57} Meta_numbersign {4 58} Meta_three {4 59} Meta_numbersign {4 60} Meta_three {4 61} Meta_numbersign {4 62} Meta_three {4 63} Meta_numbersign {4 64} three {4 65} numbersign {4 66} three {4 67} numbersign {4 68} three {4 69} numbersign {4 70} three {4 71} numbersign {4 72} Meta_three {4 73} Meta_numbersign {4 74} Meta_three {4 75} Meta_numbersign {4 76} Meta_three {4 77} Meta_numbersign {4 78} Meta_three {4 79} Meta_numbersign {4 80} three {4 81} numbersign {4 82} three {4 83} numbersign {4 84} three {4 85} numbersign {4 86} three {4 87} numbersign {4 88} Meta_three {4 89} Meta_numbersign {4 90} Meta_three {4 91} Meta_numbersign {4 92} Meta_three {4 93} Meta_numbersign {4 94} Meta_three {4 95} Meta_numbersign {4 96} three {4 97} numbersign {4 98} three {4 99} numbersign {4 100} three {4 101} numbersign {4 102} three {4 103} numbersign {4 104} Meta_three {4 105} Meta_numbersign {4 106} Meta_three {4 107} Meta_numbersign {4 108} Meta_three {4 109} Meta_numbersign {4 110} Meta_three {4 111} Meta_numbersign {4 112} three {4 113} numbersign {4 114} three {4 115} numbersign {4 116} three {4 117} numbersign {4 118} three {4 119} numbersign {4 120} Meta_three {4 121} Meta_numbersign {4 122} Meta_three {4 123} Meta_numbersign {4 124} Meta_three {4 125} Meta_numbersign {4 126} Meta_three {4 127} Meta_numbersign {5 0} four {5 1} dollar {5 2} four {5 3} dollar {5 4} four {5 5} dollar {5 6} four {5 7} dollar {5 8} Meta_four {5 9} Meta_dollar {5 10} Meta_four {5 11} Meta_dollar {5 12} Meta_four {5 13} Meta_dollar {5 14} Meta_four {5 15} Meta_dollar {5 16} four {5 17} dollar {5 18} four {5 19} dollar {5 20} four {5 21} dollar {5 22} four {5 23} dollar {5 24} Meta_four {5 25} Meta_dollar {5 26} Meta_four {5 27} Meta_dollar {5 28} Meta_four {5 29} Meta_dollar {5 30} Meta_four {5 31} Meta_dollar {5 32} four {5 33} dollar {5 34} four {5 35} dollar {5 36} four {5 37} dollar {5 38} four {5 39} dollar {5 40} Meta_four {5 41} Meta_dollar {5 42} Meta_four {5 43} Meta_dollar {5 44} Meta_four {5 45} Meta_dollar {5 46} Meta_four {5 47} Meta_dollar {5 48} four {5 49} dollar {5 50} four {5 51} dollar {5 52} four {5 53} dollar {5 54} four {5 55} dollar {5 56} Meta_four {5 57} Meta_dollar {5 58} Meta_four {5 59} Meta_dollar {5 60} Meta_four {5 61} Meta_dollar {5 62} Meta_four {5 63} Meta_dollar {5 64} four {5 65} dollar {5 66} four {5 67} dollar {5 68} four {5 69} dollar {5 70} four {5 71} dollar {5 72} Meta_four {5 73} Meta_dollar {5 74} Meta_four {5 75} Meta_dollar {5 76} Meta_four {5 77} Meta_dollar {5 78} Meta_four {5 79} Meta_dollar {5 80} four {5 81} dollar {5 82} four {5 83} dollar {5 84} four {5 85} dollar {5 86} four {5 87} dollar {5 88} Meta_four {5 89} Meta_dollar {5 90} Meta_four {5 91} Meta_dollar {5 92} Meta_four {5 93} Meta_dollar {5 94} Meta_four {5 95} Meta_dollar {5 96} four {5 97} dollar {5 98} four {5 99} dollar {5 100} four {5 101} dollar {5 102} four {5 103} dollar {5 104} Meta_four {5 105} Meta_dollar {5 106} Meta_four {5 107} Meta_dollar {5 108} Meta_four {5 109} Meta_dollar {5 110} Meta_four {5 111} Meta_dollar {5 112} four {5 113} dollar {5 114} four {5 115} dollar {5 116} four {5 117} dollar {5 118} four {5 119} dollar {5 120} Meta_four {5 121} Meta_dollar {5 122} Meta_four {5 123} Meta_dollar {5 124} Meta_four {5 125} Meta_dollar {5 126} Meta_four {5 127} Meta_dollar {6 0} five {6 1} percent {6 2} five {6 3} percent {6 4} five {6 5} percent {6 6} five {6 7} percent {6 8} Meta_five {6 9} Meta_percent {6 10} Meta_five {6 11} Meta_percent {6 12} Meta_five {6 13} Meta_percent {6 14} Meta_five {6 15} Meta_percent {6 16} five {6 17} percent {6 18} five {6 19} percent {6 20} five {6 21} percent {6 22} five {6 23} percent {6 24} Meta_five {6 25} Meta_percent {6 26} Meta_five {6 27} Meta_percent {6 28} Meta_five {6 29} Meta_percent {6 30} Meta_five {6 31} Meta_percent {6 32} five {6 33} percent {6 34} five {6 35} percent {6 36} five {6 37} percent {6 38} five {6 39} percent {6 40} Meta_five {6 41} Meta_percent {6 42} Meta_five {6 43} Meta_percent {6 44} Meta_five {6 45} Meta_percent {6 46} Meta_five {6 47} Meta_percent {6 48} five {6 49} percent {6 50} five {6 51} percent {6 52} five {6 53} percent {6 54} five {6 55} percent {6 56} Meta_five {6 57} Meta_percent {6 58} Meta_five {6 59} Meta_percent {6 60} Meta_five {6 61} Meta_percent {6 62} Meta_five {6 63} Meta_percent {6 64} five {6 65} percent {6 66} five {6 67} percent {6 68} five {6 69} percent {6 70} five {6 71} percent {6 72} Meta_five {6 73} Meta_percent {6 74} Meta_five {6 75} Meta_percent {6 76} Meta_five {6 77} Meta_percent {6 78} Meta_five {6 79} Meta_percent {6 80} five {6 81} percent {6 82} five {6 83} percent {6 84} five {6 85} percent {6 86} five {6 87} percent {6 88} Meta_five {6 89} Meta_percent {6 90} Meta_five {6 91} Meta_percent {6 92} Meta_five {6 93} Meta_percent {6 94} Meta_five {6 95} Meta_percent {6 96} five {6 97} percent {6 98} five {6 99} percent {6 100} five {6 101} percent {6 102} five {6 103} percent {6 104} Meta_five {6 105} Meta_percent {6 106} Meta_five {6 107} Meta_percent {6 108} Meta_five {6 109} Meta_percent {6 110} Meta_five {6 111} Meta_percent {6 112} five {6 113} percent {6 114} five {6 115} percent {6 116} five {6 117} percent {6 118} five {6 119} percent {6 120} Meta_five {6 121} Meta_percent {6 122} Meta_five {6 123} Meta_percent {6 124} Meta_five {6 125} Meta_percent {6 126} Meta_five {6 127} Meta_percent {7 0} six {7 1} asciicircum {7 2} six {7 3} asciicircum {7 4} Control_asciicircum {7 5} Control_asciicircum {7 6} Control_asciicircum {7 7} Control_asciicircum {7 8} Meta_six {7 9} Meta_asciicircum {7 10} Meta_six {7 11} Meta_asciicircum {7 12} Meta_Control_asciicircum {7 13} Meta_Control_asciicircum {7 14} Meta_Control_asciicircum {7 15} Meta_Control_asciicircum {7 16} six {7 17} asciicircum {7 18} six {7 19} asciicircum {7 20} Control_asciicircum {7 21} Control_asciicircum {7 22} Control_asciicircum {7 23} Control_asciicircum {7 24} Meta_six {7 25} Meta_asciicircum {7 26} Meta_six {7 27} Meta_asciicircum {7 28} Meta_Control_asciicircum {7 29} Meta_Control_asciicircum {7 30} Meta_Control_asciicircum {7 31} Meta_Control_asciicircum {7 32} six {7 33} asciicircum {7 34} six {7 35} asciicircum {7 36} Control_asciicircum {7 37} Control_asciicircum {7 38} Control_asciicircum {7 39} Control_asciicircum {7 40} Meta_six {7 41} Meta_asciicircum {7 42} Meta_six {7 43} Meta_asciicircum {7 44} Meta_Control_asciicircum {7 45} Meta_Control_asciicircum {7 46} Meta_Control_asciicircum {7 47} Meta_Control_asciicircum {7 48} six {7 49} asciicircum {7 50} six {7 51} asciicircum {7 52} Control_asciicircum {7 53} Control_asciicircum {7 54} Control_asciicircum {7 55} Control_asciicircum {7 56} Meta_six {7 57} Meta_asciicircum {7 58} Meta_six {7 59} Meta_asciicircum {7 60} Meta_Control_asciicircum {7 61} Meta_Control_asciicircum {7 62} Meta_Control_asciicircum {7 63} Meta_Control_asciicircum {7 64} six {7 65} asciicircum {7 66} six {7 67} asciicircum {7 68} Control_asciicircum {7 69} Control_asciicircum {7 70} Control_asciicircum {7 71} Control_asciicircum {7 72} Meta_six {7 73} Meta_asciicircum {7 74} Meta_six {7 75} Meta_asciicircum {7 76} Meta_Control_asciicircum {7 77} Meta_Control_asciicircum {7 78} Meta_Control_asciicircum {7 79} Meta_Control_asciicircum {7 80} six {7 81} asciicircum {7 82} six {7 83} asciicircum {7 84} Control_asciicircum {7 85} Control_asciicircum {7 86} Control_asciicircum {7 87} Control_asciicircum {7 88} Meta_six {7 89} Meta_asciicircum {7 90} Meta_six {7 91} Meta_asciicircum {7 92} Meta_Control_asciicircum {7 93} Meta_Control_asciicircum {7 94} Meta_Control_asciicircum {7 95} Meta_Control_asciicircum {7 96} six {7 97} asciicircum {7 98} six {7 99} asciicircum {7 100} Control_asciicircum {7 101} Control_asciicircum {7 102} Control_asciicircum {7 103} Control_asciicircum {7 104} Meta_six {7 105} Meta_asciicircum {7 106} Meta_six {7 107} Meta_asciicircum {7 108} Meta_Control_asciicircum {7 109} Meta_Control_asciicircum {7 110} Meta_Control_asciicircum {7 111} Meta_Control_asciicircum {7 112} six {7 113} asciicircum {7 114} six {7 115} asciicircum {7 116} Control_asciicircum {7 117} Control_asciicircum {7 118} Control_asciicircum {7 119} Control_asciicircum {7 120} Meta_six {7 121} Meta_asciicircum {7 122} Meta_six {7 123} Meta_asciicircum {7 124} Meta_Control_asciicircum {7 125} Meta_Control_asciicircum {7 126} Meta_Control_asciicircum {7 127} Meta_Control_asciicircum {8 0} seven {8 1} ampersand {8 2} seven {8 3} ampersand {8 4} seven {8 5} ampersand {8 6} seven {8 7} ampersand {8 8} Meta_seven {8 9} Meta_ampersand {8 10} Meta_seven {8 11} Meta_ampersand {8 12} Meta_seven {8 13} Meta_ampersand {8 14} Meta_seven {8 15} Meta_ampersand {8 16} seven {8 17} ampersand {8 18} seven {8 19} ampersand {8 20} seven {8 21} ampersand {8 22} seven {8 23} ampersand {8 24} Meta_seven {8 25} Meta_ampersand {8 26} Meta_seven {8 27} Meta_ampersand {8 28} Meta_seven {8 29} Meta_ampersand {8 30} Meta_seven {8 31} Meta_ampersand {8 32} seven {8 33} ampersand {8 34} seven {8 35} ampersand {8 36} seven {8 37} ampersand {8 38} seven {8 39} ampersand {8 40} Meta_seven {8 41} Meta_ampersand {8 42} Meta_seven {8 43} Meta_ampersand {8 44} Meta_seven {8 45} Meta_ampersand {8 46} Meta_seven {8 47} Meta_ampersand {8 48} seven {8 49} ampersand {8 50} seven {8 51} ampersand {8 52} seven {8 53} ampersand {8 54} seven {8 55} ampersand {8 56} Meta_seven {8 57} Meta_ampersand {8 58} Meta_seven {8 59} Meta_ampersand {8 60} Meta_seven {8 61} Meta_ampersand {8 62} Meta_seven {8 63} Meta_ampersand {8 64} seven {8 65} ampersand {8 66} seven {8 67} ampersand {8 68} seven {8 69} ampersand {8 70} seven {8 71} ampersand {8 72} Meta_seven {8 73} Meta_ampersand {8 74} Meta_seven {8 75} Meta_ampersand {8 76} Meta_seven {8 77} Meta_ampersand {8 78} Meta_seven {8 79} Meta_ampersand {8 80} seven {8 81} ampersand {8 82} seven {8 83} ampersand {8 84} seven {8 85} ampersand {8 86} seven {8 87} ampersand {8 88} Meta_seven {8 89} Meta_ampersand {8 90} Meta_seven {8 91} Meta_ampersand {8 92} Meta_seven {8 93} Meta_ampersand {8 94} Meta_seven {8 95} Meta_ampersand {8 96} seven {8 97} ampersand {8 98} seven {8 99} ampersand {8 100} seven {8 101} ampersand {8 102} seven {8 103} ampersand {8 104} Meta_seven {8 105} Meta_ampersand {8 106} Meta_seven {8 107} Meta_ampersand {8 108} Meta_seven {8 109} Meta_ampersand {8 110} Meta_seven {8 111} Meta_ampersand {8 112} seven {8 113} ampersand {8 114} seven {8 115} ampersand {8 116} seven {8 117} ampersand {8 118} seven {8 119} ampersand {8 120} Meta_seven {8 121} Meta_ampersand {8 122} Meta_seven {8 123} Meta_ampersand {8 124} Meta_seven {8 125} Meta_ampersand {8 126} Meta_seven {8 127} Meta_ampersand {9 0} eight {9 1} asterisk {9 2} eight {9 3} asterisk {9 4} eight {9 5} asterisk {9 6} eight {9 7} asterisk {9 8} Meta_eight {9 9} Meta_asterisk {9 10} Meta_eight {9 11} Meta_asterisk {9 12} Meta_eight {9 13} Meta_asterisk {9 14} Meta_eight {9 15} Meta_asterisk {9 16} eight {9 17} asterisk {9 18} eight {9 19} asterisk {9 20} eight {9 21} asterisk {9 22} eight {9 23} asterisk {9 24} Meta_eight {9 25} Meta_asterisk {9 26} Meta_eight {9 27} Meta_asterisk {9 28} Meta_eight {9 29} Meta_asterisk {9 30} Meta_eight {9 31} Meta_asterisk {9 32} eight {9 33} asterisk {9 34} eight {9 35} asterisk {9 36} eight {9 37} asterisk {9 38} eight {9 39} asterisk {9 40} Meta_eight {9 41} Meta_asterisk {9 42} Meta_eight {9 43} Meta_asterisk {9 44} Meta_eight {9 45} Meta_asterisk {9 46} Meta_eight {9 47} Meta_asterisk {9 48} eight {9 49} asterisk {9 50} eight {9 51} asterisk {9 52} eight {9 53} asterisk {9 54} eight {9 55} asterisk {9 56} Meta_eight {9 57} Meta_asterisk {9 58} Meta_eight {9 59} Meta_asterisk {9 60} Meta_eight {9 61} Meta_asterisk {9 62} Meta_eight {9 63} Meta_asterisk {9 64} eight {9 65} asterisk {9 66} eight {9 67} asterisk {9 68} eight {9 69} asterisk {9 70} eight {9 71} asterisk {9 72} Meta_eight {9 73} Meta_asterisk {9 74} Meta_eight {9 75} Meta_asterisk {9 76} Meta_eight {9 77} Meta_asterisk {9 78} Meta_eight {9 79} Meta_asterisk {9 80} eight {9 81} asterisk {9 82} eight {9 83} asterisk {9 84} eight {9 85} asterisk {9 86} eight {9 87} asterisk {9 88} Meta_eight {9 89} Meta_asterisk {9 90} Meta_eight {9 91} Meta_asterisk {9 92} Meta_eight {9 93} Meta_asterisk {9 94} Meta_eight {9 95} Meta_asterisk {9 96} eight {9 97} asterisk {9 98} eight {9 99} asterisk {9 100} eight {9 101} asterisk {9 102} eight {9 103} asterisk {9 104} Meta_eight {9 105} Meta_asterisk {9 106} Meta_eight {9 107} Meta_asterisk {9 108} Meta_eight {9 109} Meta_asterisk {9 110} Meta_eight {9 111} Meta_asterisk {9 112} eight {9 113} asterisk {9 114} eight {9 115} asterisk {9 116} eight {9 117} asterisk {9 118} eight {9 119} asterisk {9 120} Meta_eight {9 121} Meta_asterisk {9 122} Meta_eight {9 123} Meta_asterisk {9 124} Meta_eight {9 125} Meta_asterisk {9 126} Meta_eight {9 127} Meta_asterisk {10 0} nine {10 1} parenleft {10 2} nine {10 3} parenleft {10 4} nine {10 5} parenleft {10 6} nine {10 7} parenleft {10 8} Meta_nine {10 9} Meta_parenleft {10 10} Meta_nine {10 11} Meta_parenleft {10 12} Meta_nine {10 13} Meta_parenleft {10 14} Meta_nine {10 15} Meta_parenleft {10 16} nine {10 17} parenleft {10 18} nine {10 19} parenleft {10 20} nine {10 21} parenleft {10 22} nine {10 23} parenleft {10 24} Meta_nine {10 25} Meta_parenleft {10 26} Meta_nine {10 27} Meta_parenleft {10 28} Meta_nine {10 29} Meta_parenleft {10 30} Meta_nine {10 31} Meta_parenleft {10 32} nine {10 33} parenleft {10 34} nine {10 35} parenleft {10 36} nine {10 37} parenleft {10 38} nine {10 39} parenleft {10 40} Meta_nine {10 41} Meta_parenleft {10 42} Meta_nine {10 43} Meta_parenleft {10 44} Meta_nine {10 45} Meta_parenleft {10 46} Meta_nine {10 47} Meta_parenleft {10 48} nine {10 49} parenleft {10 50} nine {10 51} parenleft {10 52} nine {10 53} parenleft {10 54} nine {10 55} parenleft {10 56} Meta_nine {10 57} Meta_parenleft {10 58} Meta_nine {10 59} Meta_parenleft {10 60} Meta_nine {10 61} Meta_parenleft {10 62} Meta_nine {10 63} Meta_parenleft {10 64} nine {10 65} parenleft {10 66} nine {10 67} parenleft {10 68} nine {10 69} parenleft {10 70} nine {10 71} parenleft {10 72} Meta_nine {10 73} Meta_parenleft {10 74} Meta_nine {10 75} Meta_parenleft {10 76} Meta_nine {10 77} Meta_parenleft {10 78} Meta_nine {10 79} Meta_parenleft {10 80} nine {10 81} parenleft {10 82} nine {10 83} parenleft {10 84} nine {10 85} parenleft {10 86} nine {10 87} parenleft {10 88} Meta_nine {10 89} Meta_parenleft {10 90} Meta_nine {10 91} Meta_parenleft {10 92} Meta_nine {10 93} Meta_parenleft {10 94} Meta_nine {10 95} Meta_parenleft {10 96} nine {10 97} parenleft {10 98} nine {10 99} parenleft {10 100} nine {10 101} parenleft {10 102} nine {10 103} parenleft {10 104} Meta_nine {10 105} Meta_parenleft {10 106} Meta_nine {10 107} Meta_parenleft {10 108} Meta_nine {10 109} Meta_parenleft {10 110} Meta_nine {10 111} Meta_parenleft {10 112} nine {10 113} parenleft {10 114} nine {10 115} parenleft {10 116} nine {10 117} parenleft {10 118} nine {10 119} parenleft {10 120} Meta_nine {10 121} Meta_parenleft {10 122} Meta_nine {10 123} Meta_parenleft {10 124} Meta_nine {10 125} Meta_parenleft {10 126} Meta_nine {10 127} Meta_parenleft {11 0} zero {11 1} parenright {11 2} zero {11 3} parenright {11 4} zero {11 5} parenright {11 6} zero {11 7} parenright {11 8} Meta_zero {11 9} Meta_parenright {11 10} Meta_zero {11 11} Meta_parenright {11 12} Meta_zero {11 13} Meta_parenright {11 14} Meta_zero {11 15} Meta_parenright {11 16} zero {11 17} parenright {11 18} zero {11 19} parenright {11 20} zero {11 21} parenright {11 22} zero {11 23} parenright {11 24} Meta_zero {11 25} Meta_parenright {11 26} Meta_zero {11 27} Meta_parenright {11 28} Meta_zero {11 29} Meta_parenright {11 30} Meta_zero {11 31} Meta_parenright {11 32} zero {11 33} parenright {11 34} zero {11 35} parenright {11 36} zero {11 37} parenright {11 38} zero {11 39} parenright {11 40} Meta_zero {11 41} Meta_parenright {11 42} Meta_zero {11 43} Meta_parenright {11 44} Meta_zero {11 45} Meta_parenright {11 46} Meta_zero {11 47} Meta_parenright {11 48} zero {11 49} parenright {11 50} zero {11 51} parenright {11 52} zero {11 53} parenright {11 54} zero {11 55} parenright {11 56} Meta_zero {11 57} Meta_parenright {11 58} Meta_zero {11 59} Meta_parenright {11 60} Meta_zero {11 61} Meta_parenright {11 62} Meta_zero {11 63} Meta_parenright {11 64} zero {11 65} parenright {11 66} zero {11 67} parenright {11 68} zero {11 69} parenright {11 70} zero {11 71} parenright {11 72} Meta_zero {11 73} Meta_parenright {11 74} Meta_zero {11 75} Meta_parenright {11 76} Meta_zero {11 77} Meta_parenright {11 78} Meta_zero {11 79} Meta_parenright {11 80} zero {11 81} parenright {11 82} zero {11 83} parenright {11 84} zero {11 85} parenright {11 86} zero {11 87} parenright {11 88} Meta_zero {11 89} Meta_parenright {11 90} Meta_zero {11 91} Meta_parenright {11 92} Meta_zero {11 93} Meta_parenright {11 94} Meta_zero {11 95} Meta_parenright {11 96} zero {11 97} parenright {11 98} zero {11 99} parenright {11 100} zero {11 101} parenright {11 102} zero {11 103} parenright {11 104} Meta_zero {11 105} Meta_parenright {11 106} Meta_zero {11 107} Meta_parenright {11 108} Meta_zero {11 109} Meta_parenright {11 110} Meta_zero {11 111} Meta_parenright {11 112} zero {11 113} parenright {11 114} zero {11 115} parenright {11 116} zero {11 117} parenright {11 118} zero {11 119} parenright {11 120} Meta_zero {11 121} Meta_parenright {11 122} Meta_zero {11 123} Meta_parenright {11 124} Meta_zero {11 125} Meta_parenright {11 126} Meta_zero {11 127} Meta_parenright {12 0} minus {12 1} underscore {12 2} minus {12 3} underscore {12 4} Control_underscore {12 5} Control_underscore {12 6} Control_underscore {12 7} Control_underscore {12 8} Meta_minus {12 9} Meta_underscore {12 10} Meta_minus {12 11} Meta_underscore {12 12} Meta_Control_underscore {12 13} Meta_Control_underscore {12 14} Meta_Control_underscore {12 15} Meta_Control_underscore {12 16} minus {12 17} underscore {12 18} minus {12 19} underscore {12 20} Control_underscore {12 21} Control_underscore {12 22} Control_underscore {12 23} Control_underscore {12 24} Meta_minus {12 25} Meta_underscore {12 26} Meta_minus {12 27} Meta_underscore {12 28} Meta_Control_underscore {12 29} Meta_Control_underscore {12 30} Meta_Control_underscore {12 31} Meta_Control_underscore {12 32} minus {12 33} underscore {12 34} minus {12 35} underscore {12 36} Control_underscore {12 37} Control_underscore {12 38} Control_underscore {12 39} Control_underscore {12 40} Meta_minus {12 41} Meta_underscore {12 42} Meta_minus {12 43} Meta_underscore {12 44} Meta_Control_underscore {12 45} Meta_Control_underscore {12 46} Meta_Control_underscore {12 47} Meta_Control_underscore {12 48} minus {12 49} underscore {12 50} minus {12 51} underscore {12 52} Control_underscore {12 53} Control_underscore {12 54} Control_underscore {12 55} Control_underscore {12 56} Meta_minus {12 57} Meta_underscore {12 58} Meta_minus {12 59} Meta_underscore {12 60} Meta_Control_underscore {12 61} Meta_Control_underscore {12 62} Meta_Control_underscore {12 63} Meta_Control_underscore {12 64} minus {12 65} underscore {12 66} minus {12 67} underscore {12 68} Control_underscore {12 69} Control_underscore {12 70} Control_underscore {12 71} Control_underscore {12 72} Meta_minus {12 73} Meta_underscore {12 74} Meta_minus {12 75} Meta_underscore {12 76} Meta_Control_underscore {12 77} Meta_Control_underscore {12 78} Meta_Control_underscore {12 79} Meta_Control_underscore {12 80} minus {12 81} underscore {12 82} minus {12 83} underscore {12 84} Control_underscore {12 85} Control_underscore {12 86} Control_underscore {12 87} Control_underscore {12 88} Meta_minus {12 89} Meta_underscore {12 90} Meta_minus {12 91} Meta_underscore {12 92} Meta_Control_underscore {12 93} Meta_Control_underscore {12 94} Meta_Control_underscore {12 95} Meta_Control_underscore {12 96} minus {12 97} underscore {12 98} minus {12 99} underscore {12 100} Control_underscore {12 101} Control_underscore {12 102} Control_underscore {12 103} Control_underscore {12 104} Meta_minus {12 105} Meta_underscore {12 106} Meta_minus {12 107} Meta_underscore {12 108} Meta_Control_underscore {12 109} Meta_Control_underscore {12 110} Meta_Control_underscore {12 111} Meta_Control_underscore {12 112} minus {12 113} underscore {12 114} minus {12 115} underscore {12 116} Control_underscore {12 117} Control_underscore {12 118} Control_underscore {12 119} Control_underscore {12 120} Meta_minus {12 121} Meta_underscore {12 122} Meta_minus {12 123} Meta_underscore {12 124} Meta_Control_underscore {12 125} Meta_Control_underscore {12 126} Meta_Control_underscore {12 127} Meta_Control_underscore {13 0} equal {13 1} plus {13 2} equal {13 3} plus {13 4} equal {13 5} plus {13 6} equal {13 7} plus {13 8} Meta_equal {13 9} Meta_plus {13 10} Meta_equal {13 11} Meta_plus {13 12} Meta_equal {13 13} Meta_plus {13 14} Meta_equal {13 15} Meta_plus {13 16} equal {13 17} plus {13 18} equal {13 19} plus {13 20} equal {13 21} plus {13 22} equal {13 23} plus {13 24} Meta_equal {13 25} Meta_plus {13 26} Meta_equal {13 27} Meta_plus {13 28} Meta_equal {13 29} Meta_plus {13 30} Meta_equal {13 31} Meta_plus {13 32} equal {13 33} plus {13 34} equal {13 35} plus {13 36} equal {13 37} plus {13 38} equal {13 39} plus {13 40} Meta_equal {13 41} Meta_plus {13 42} Meta_equal {13 43} Meta_plus {13 44} Meta_equal {13 45} Meta_plus {13 46} Meta_equal {13 47} Meta_plus {13 48} equal {13 49} plus {13 50} equal {13 51} plus {13 52} equal {13 53} plus {13 54} equal {13 55} plus {13 56} Meta_equal {13 57} Meta_plus {13 58} Meta_equal {13 59} Meta_plus {13 60} Meta_equal {13 61} Meta_plus {13 62} Meta_equal {13 63} Meta_plus {13 64} equal {13 65} plus {13 66} equal {13 67} plus {13 68} equal {13 69} plus {13 70} equal {13 71} plus {13 72} Meta_equal {13 73} Meta_plus {13 74} Meta_equal {13 75} Meta_plus {13 76} Meta_equal {13 77} Meta_plus {13 78} Meta_equal {13 79} Meta_plus {13 80} equal {13 81} plus {13 82} equal {13 83} plus {13 84} equal {13 85} plus {13 86} equal {13 87} plus {13 88} Meta_equal {13 89} Meta_plus {13 90} Meta_equal {13 91} Meta_plus {13 92} Meta_equal {13 93} Meta_plus {13 94} Meta_equal {13 95} Meta_plus {13 96} equal {13 97} plus {13 98} equal {13 99} plus {13 100} equal {13 101} plus {13 102} equal {13 103} plus {13 104} Meta_equal {13 105} Meta_plus {13 106} Meta_equal {13 107} Meta_plus {13 108} Meta_equal {13 109} Meta_plus {13 110} Meta_equal {13 111} Meta_plus {13 112} equal {13 113} plus {13 114} equal {13 115} plus {13 116} equal {13 117} plus {13 118} equal {13 119} plus {13 120} Meta_equal {13 121} Meta_plus {13 122} Meta_equal {13 123} Meta_plus {13 124} Meta_equal {13 125} Meta_plus {13 126} Meta_equal {13 127} Meta_plus {14 0} Delete {14 1} Delete {14 2} Delete {14 3} Delete {14 4} BackSpace {14 5} BackSpace {14 6} BackSpace {14 7} BackSpace {14 8} Meta_Delete {14 9} Meta_Delete {14 10} Meta_Delete {14 11} Meta_Delete {14 12} Meta_BackSpace {14 13} Meta_BackSpace {14 14} Meta_BackSpace {14 15} Meta_BackSpace {14 16} Delete {14 17} Delete {14 18} Delete {14 19} Delete {14 20} BackSpace {14 21} BackSpace {14 22} BackSpace {14 23} BackSpace {14 24} Meta_Delete {14 25} Meta_Delete {14 26} Meta_Delete {14 27} Meta_Delete {14 28} Meta_BackSpace {14 29} Meta_BackSpace {14 30} Meta_BackSpace {14 31} Meta_BackSpace {14 32} Delete {14 33} Delete {14 34} Delete {14 35} Delete {14 36} BackSpace {14 37} BackSpace {14 38} BackSpace {14 39} BackSpace {14 40} Meta_Delete {14 41} Meta_Delete {14 42} Meta_Delete {14 43} Meta_Delete {14 44} Meta_BackSpace {14 45} Meta_BackSpace {14 46} Meta_BackSpace {14 47} Meta_BackSpace {14 48} Delete {14 49} Delete {14 50} Delete {14 51} Delete {14 52} BackSpace {14 53} BackSpace {14 54} BackSpace {14 55} BackSpace {14 56} Meta_Delete {14 57} Meta_Delete {14 58} Meta_Delete {14 59} Meta_Delete {14 60} Meta_BackSpace {14 61} Meta_BackSpace {14 62} Meta_BackSpace {14 63} Meta_BackSpace {14 64} Delete {14 65} Delete {14 66} Delete {14 67} Delete {14 68} BackSpace {14 69} BackSpace {14 70} BackSpace {14 71} BackSpace {14 72} Meta_Delete {14 73} Meta_Delete {14 74} Meta_Delete {14 75} Meta_Delete {14 76} Meta_BackSpace {14 77} Meta_BackSpace {14 78} Meta_BackSpace {14 79} Meta_BackSpace {14 80} Delete {14 81} Delete {14 82} Delete {14 83} Delete {14 84} BackSpace {14 85} BackSpace {14 86} BackSpace {14 87} BackSpace {14 88} Meta_Delete {14 89} Meta_Delete {14 90} Meta_Delete {14 91} Meta_Delete {14 92} Meta_BackSpace {14 93} Meta_BackSpace {14 94} Meta_BackSpace {14 95} Meta_BackSpace {14 96} Delete {14 97} Delete {14 98} Delete {14 99} Delete {14 100} BackSpace {14 101} BackSpace {14 102} BackSpace {14 103} BackSpace {14 104} Meta_Delete {14 105} Meta_Delete {14 106} Meta_Delete {14 107} Meta_Delete {14 108} Meta_BackSpace {14 109} Meta_BackSpace {14 110} Meta_BackSpace {14 111} Meta_BackSpace {14 112} Delete {14 113} Delete {14 114} Delete {14 115} Delete {14 116} BackSpace {14 117} BackSpace {14 118} BackSpace {14 119} BackSpace {14 120} Meta_Delete {14 121} Meta_Delete {14 122} Meta_Delete {14 123} Meta_Delete {14 124} Meta_BackSpace {14 125} Meta_BackSpace {14 126} Meta_BackSpace {14 127} Meta_BackSpace {15 0} Tab {15 1} Meta_Tab {15 2} Tab {15 3} Meta_Tab {15 4} Tab {15 5} Tab {15 6} Tab {15 7} Tab {15 8} Meta_Tab {15 9} Meta_Tab {15 10} Meta_Tab {15 11} Meta_Tab {15 12} Meta_Tab {15 13} Meta_Tab {15 14} Meta_Tab {15 15} Meta_Tab {15 16} Tab {15 17} Meta_Tab {15 18} Tab {15 19} Meta_Tab {15 20} Tab {15 21} Tab {15 22} Tab {15 23} Tab {15 24} Meta_Tab {15 25} Meta_Tab {15 26} Meta_Tab {15 27} Meta_Tab {15 28} Meta_Tab {15 29} Meta_Tab {15 30} Meta_Tab {15 31} Meta_Tab {15 32} Tab {15 33} Meta_Tab {15 34} Tab {15 35} Meta_Tab {15 36} Tab {15 37} Tab {15 38} Tab {15 39} Tab {15 40} Meta_Tab {15 41} Meta_Tab {15 42} Meta_Tab {15 43} Meta_Tab {15 44} Meta_Tab {15 45} Meta_Tab {15 46} Meta_Tab {15 47} Meta_Tab {15 48} Tab {15 49} Meta_Tab {15 50} Tab {15 51} Meta_Tab {15 52} Tab {15 53} Tab {15 54} Tab {15 55} Tab {15 56} Meta_Tab {15 57} Meta_Tab {15 58} Meta_Tab {15 59} Meta_Tab {15 60} Meta_Tab {15 61} Meta_Tab {15 62} Meta_Tab {15 63} Meta_Tab {15 64} Tab {15 65} Meta_Tab {15 66} Tab {15 67} Meta_Tab {15 68} Tab {15 69} Tab {15 70} Tab {15 71} Tab {15 72} Meta_Tab {15 73} Meta_Tab {15 74} Meta_Tab {15 75} Meta_Tab {15 76} Meta_Tab {15 77} Meta_Tab {15 78} Meta_Tab {15 79} Meta_Tab {15 80} Tab {15 81} Meta_Tab {15 82} Tab {15 83} Meta_Tab {15 84} Tab {15 85} Tab {15 86} Tab {15 87} Tab {15 88} Meta_Tab {15 89} Meta_Tab {15 90} Meta_Tab {15 91} Meta_Tab {15 92} Meta_Tab {15 93} Meta_Tab {15 94} Meta_Tab {15 95} Meta_Tab {15 96} Tab {15 97} Meta_Tab {15 98} Tab {15 99} Meta_Tab {15 100} Tab {15 101} Tab {15 102} Tab {15 103} Tab {15 104} Meta_Tab {15 105} Meta_Tab {15 106} Meta_Tab {15 107} Meta_Tab {15 108} Meta_Tab {15 109} Meta_Tab {15 110} Meta_Tab {15 111} Meta_Tab {15 112} Tab {15 113} Meta_Tab {15 114} Tab {15 115} Meta_Tab {15 116} Tab {15 117} Tab {15 118} Tab {15 119} Tab {15 120} Meta_Tab {15 121} Meta_Tab {15 122} Meta_Tab {15 123} Meta_Tab {15 124} Meta_Tab {15 125} Meta_Tab {15 126} Meta_Tab {15 127} Meta_Tab {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} Control_q {16 5} Control_q {16 6} Control_q {16 7} Control_q {16 8} Meta_q {16 9} Meta_Q {16 10} Meta_q {16 11} Meta_Q {16 12} Meta_Control_q {16 13} Meta_Control_q {16 14} Meta_Control_q {16 15} Meta_Control_q {16 16} q {16 17} Q {16 18} q {16 19} Q {16 20} Control_q {16 21} Control_q {16 22} Control_q {16 23} Control_q {16 24} Meta_q {16 25} Meta_Q {16 26} Meta_q {16 27} Meta_Q {16 28} Meta_Control_q {16 29} Meta_Control_q {16 30} Meta_Control_q {16 31} Meta_Control_q {16 32} q {16 33} Q {16 34} q {16 35} Q {16 36} Control_q {16 37} Control_q {16 38} Control_q {16 39} Control_q {16 40} Meta_q {16 41} Meta_Q {16 42} Meta_q {16 43} Meta_Q {16 44} Meta_Control_q {16 45} Meta_Control_q {16 46} Meta_Control_q {16 47} Meta_Control_q {16 48} q {16 49} Q {16 50} q {16 51} Q {16 52} Control_q {16 53} Control_q {16 54} Control_q {16 55} Control_q {16 56} Meta_q {16 57} Meta_Q {16 58} Meta_q {16 59} Meta_Q {16 60} Meta_Control_q {16 61} Meta_Control_q {16 62} Meta_Control_q {16 63} Meta_Control_q {16 64} Q {16 65} q {16 66} Q {16 67} q {16 68} Control_q {16 69} Control_q {16 70} Control_q {16 71} Control_q {16 72} Meta_q {16 73} Meta_Q {16 74} Meta_q {16 75} Meta_Q {16 76} Meta_Control_q {16 77} Meta_Control_q {16 78} Meta_Control_q {16 79} Meta_Control_q {16 80} Q {16 81} q {16 82} Q {16 83} q {16 84} Control_q {16 85} Control_q {16 86} Control_q {16 87} Control_q {16 88} Meta_q {16 89} Meta_Q {16 90} Meta_q {16 91} Meta_Q {16 92} Meta_Control_q {16 93} Meta_Control_q {16 94} Meta_Control_q {16 95} Meta_Control_q {16 96} Q {16 97} q {16 98} Q {16 99} q {16 100} Control_q {16 101} Control_q {16 102} Control_q {16 103} Control_q {16 104} Meta_q {16 105} Meta_Q {16 106} Meta_q {16 107} Meta_Q {16 108} Meta_Control_q {16 109} Meta_Control_q {16 110} Meta_Control_q {16 111} Meta_Control_q {16 112} Q {16 113} q {16 114} Q {16 115} q {16 116} Control_q {16 117} Control_q {16 118} Control_q {16 119} Control_q {16 120} Meta_q {16 121} Meta_Q {16 122} Meta_q {16 123} Meta_Q {16 124} Meta_Control_q {16 125} Meta_Control_q {16 126} Meta_Control_q {16 127} Meta_Control_q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} Control_w {17 5} Control_w {17 6} Control_w {17 7} Control_w {17 8} Meta_w {17 9} Meta_W {17 10} Meta_w {17 11} Meta_W {17 12} Meta_Control_w {17 13} Meta_Control_w {17 14} Meta_Control_w {17 15} Meta_Control_w {17 16} w {17 17} W {17 18} w {17 19} W {17 20} Control_w {17 21} Control_w {17 22} Control_w {17 23} Control_w {17 24} Meta_w {17 25} Meta_W {17 26} Meta_w {17 27} Meta_W {17 28} Meta_Control_w {17 29} Meta_Control_w {17 30} Meta_Control_w {17 31} Meta_Control_w {17 32} w {17 33} W {17 34} w {17 35} W {17 36} Control_w {17 37} Control_w {17 38} Control_w {17 39} Control_w {17 40} Meta_w {17 41} Meta_W {17 42} Meta_w {17 43} Meta_W {17 44} Meta_Control_w {17 45} Meta_Control_w {17 46} Meta_Control_w {17 47} Meta_Control_w {17 48} w {17 49} W {17 50} w {17 51} W {17 52} Control_w {17 53} Control_w {17 54} Control_w {17 55} Control_w {17 56} Meta_w {17 57} Meta_W {17 58} Meta_w {17 59} Meta_W {17 60} Meta_Control_w {17 61} Meta_Control_w {17 62} Meta_Control_w {17 63} Meta_Control_w {17 64} W {17 65} w {17 66} W {17 67} w {17 68} Control_w {17 69} Control_w {17 70} Control_w {17 71} Control_w {17 72} Meta_w {17 73} Meta_W {17 74} Meta_w {17 75} Meta_W {17 76} Meta_Control_w {17 77} Meta_Control_w {17 78} Meta_Control_w {17 79} Meta_Control_w {17 80} W {17 81} w {17 82} W {17 83} w {17 84} Control_w {17 85} Control_w {17 86} Control_w {17 87} Control_w {17 88} Meta_w {17 89} Meta_W {17 90} Meta_w {17 91} Meta_W {17 92} Meta_Control_w {17 93} Meta_Control_w {17 94} Meta_Control_w {17 95} Meta_Control_w {17 96} W {17 97} w {17 98} W {17 99} w {17 100} Control_w {17 101} Control_w {17 102} Control_w {17 103} Control_w {17 104} Meta_w {17 105} Meta_W {17 106} Meta_w {17 107} Meta_W {17 108} Meta_Control_w {17 109} Meta_Control_w {17 110} Meta_Control_w {17 111} Meta_Control_w {17 112} W {17 113} w {17 114} W {17 115} w {17 116} Control_w {17 117} Control_w {17 118} Control_w {17 119} Control_w {17 120} Meta_w {17 121} Meta_W {17 122} Meta_w {17 123} Meta_W {17 124} Meta_Control_w {17 125} Meta_Control_w {17 126} Meta_Control_w {17 127} Meta_Control_w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} Control_e {18 5} Control_e {18 6} Control_e {18 7} Control_e {18 8} Meta_e {18 9} Meta_E {18 10} Meta_e {18 11} Meta_E {18 12} Meta_Control_e {18 13} Meta_Control_e {18 14} Meta_Control_e {18 15} Meta_Control_e {18 16} e {18 17} E {18 18} e {18 19} E {18 20} Control_e {18 21} Control_e {18 22} Control_e {18 23} Control_e {18 24} Meta_e {18 25} Meta_E {18 26} Meta_e {18 27} Meta_E {18 28} Meta_Control_e {18 29} Meta_Control_e {18 30} Meta_Control_e {18 31} Meta_Control_e {18 32} e {18 33} E {18 34} e {18 35} E {18 36} Control_e {18 37} Control_e {18 38} Control_e {18 39} Control_e {18 40} Meta_e {18 41} Meta_E {18 42} Meta_e {18 43} Meta_E {18 44} Meta_Control_e {18 45} Meta_Control_e {18 46} Meta_Control_e {18 47} Meta_Control_e {18 48} e {18 49} E {18 50} e {18 51} E {18 52} Control_e {18 53} Control_e {18 54} Control_e {18 55} Control_e {18 56} Meta_e {18 57} Meta_E {18 58} Meta_e {18 59} Meta_E {18 60} Meta_Control_e {18 61} Meta_Control_e {18 62} Meta_Control_e {18 63} Meta_Control_e {18 64} E {18 65} e {18 66} E {18 67} e {18 68} Control_e {18 69} Control_e {18 70} Control_e {18 71} Control_e {18 72} Meta_e {18 73} Meta_E {18 74} Meta_e {18 75} Meta_E {18 76} Meta_Control_e {18 77} Meta_Control_e {18 78} Meta_Control_e {18 79} Meta_Control_e {18 80} E {18 81} e {18 82} E {18 83} e {18 84} Control_e {18 85} Control_e {18 86} Control_e {18 87} Control_e {18 88} Meta_e {18 89} Meta_E {18 90} Meta_e {18 91} Meta_E {18 92} Meta_Control_e {18 93} Meta_Control_e {18 94} Meta_Control_e {18 95} Meta_Control_e {18 96} E {18 97} e {18 98} E {18 99} e {18 100} Control_e {18 101} Control_e {18 102} Control_e {18 103} Control_e {18 104} Meta_e {18 105} Meta_E {18 106} Meta_e {18 107} Meta_E {18 108} Meta_Control_e {18 109} Meta_Control_e {18 110} Meta_Control_e {18 111} Meta_Control_e {18 112} E {18 113} e {18 114} E {18 115} e {18 116} Control_e {18 117} Control_e {18 118} Control_e {18 119} Control_e {18 120} Meta_e {18 121} Meta_E {18 122} Meta_e {18 123} Meta_E {18 124} Meta_Control_e {18 125} Meta_Control_e {18 126} Meta_Control_e {18 127} Meta_Control_e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} Control_r {19 5} Control_r {19 6} Control_r {19 7} Control_r {19 8} Meta_r {19 9} Meta_R {19 10} Meta_r {19 11} Meta_R {19 12} Meta_Control_r {19 13} Meta_Control_r {19 14} Meta_Control_r {19 15} Meta_Control_r {19 16} r {19 17} R {19 18} r {19 19} R {19 20} Control_r {19 21} Control_r {19 22} Control_r {19 23} Control_r {19 24} Meta_r {19 25} Meta_R {19 26} Meta_r {19 27} Meta_R {19 28} Meta_Control_r {19 29} Meta_Control_r {19 30} Meta_Control_r {19 31} Meta_Control_r {19 32} r {19 33} R {19 34} r {19 35} R {19 36} Control_r {19 37} Control_r {19 38} Control_r {19 39} Control_r {19 40} Meta_r {19 41} Meta_R {19 42} Meta_r {19 43} Meta_R {19 44} Meta_Control_r {19 45} Meta_Control_r {19 46} Meta_Control_r {19 47} Meta_Control_r {19 48} r {19 49} R {19 50} r {19 51} R {19 52} Control_r {19 53} Control_r {19 54} Control_r {19 55} Control_r {19 56} Meta_r {19 57} Meta_R {19 58} Meta_r {19 59} Meta_R {19 60} Meta_Control_r {19 61} Meta_Control_r {19 62} Meta_Control_r {19 63} Meta_Control_r {19 64} R {19 65} r {19 66} R {19 67} r {19 68} Control_r {19 69} Control_r {19 70} Control_r {19 71} Control_r {19 72} Meta_r {19 73} Meta_R {19 74} Meta_r {19 75} Meta_R {19 76} Meta_Control_r {19 77} Meta_Control_r {19 78} Meta_Control_r {19 79} Meta_Control_r {19 80} R {19 81} r {19 82} R {19 83} r {19 84} Control_r {19 85} Control_r {19 86} Control_r {19 87} Control_r {19 88} Meta_r {19 89} Meta_R {19 90} Meta_r {19 91} Meta_R {19 92} Meta_Control_r {19 93} Meta_Control_r {19 94} Meta_Control_r {19 95} Meta_Control_r {19 96} R {19 97} r {19 98} R {19 99} r {19 100} Control_r {19 101} Control_r {19 102} Control_r {19 103} Control_r {19 104} Meta_r {19 105} Meta_R {19 106} Meta_r {19 107} Meta_R {19 108} Meta_Control_r {19 109} Meta_Control_r {19 110} Meta_Control_r {19 111} Meta_Control_r {19 112} R {19 113} r {19 114} R {19 115} r {19 116} Control_r {19 117} Control_r {19 118} Control_r {19 119} Control_r {19 120} Meta_r {19 121} Meta_R {19 122} Meta_r {19 123} Meta_R {19 124} Meta_Control_r {19 125} Meta_Control_r {19 126} Meta_Control_r {19 127} Meta_Control_r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} Control_t {20 5} Control_t {20 6} Control_t {20 7} Control_t {20 8} Meta_t {20 9} Meta_T {20 10} Meta_t {20 11} Meta_T {20 12} Meta_Control_t {20 13} Meta_Control_t {20 14} Meta_Control_t {20 15} Meta_Control_t {20 16} t {20 17} T {20 18} t {20 19} T {20 20} Control_t {20 21} Control_t {20 22} Control_t {20 23} Control_t {20 24} Meta_t {20 25} Meta_T {20 26} Meta_t {20 27} Meta_T {20 28} Meta_Control_t {20 29} Meta_Control_t {20 30} Meta_Control_t {20 31} Meta_Control_t {20 32} t {20 33} T {20 34} t {20 35} T {20 36} Control_t {20 37} Control_t {20 38} Control_t {20 39} Control_t {20 40} Meta_t {20 41} Meta_T {20 42} Meta_t {20 43} Meta_T {20 44} Meta_Control_t {20 45} Meta_Control_t {20 46} Meta_Control_t {20 47} Meta_Control_t {20 48} t {20 49} T {20 50} t {20 51} T {20 52} Control_t {20 53} Control_t {20 54} Control_t {20 55} Control_t {20 56} Meta_t {20 57} Meta_T {20 58} Meta_t {20 59} Meta_T {20 60} Meta_Control_t {20 61} Meta_Control_t {20 62} Meta_Control_t {20 63} Meta_Control_t {20 64} T {20 65} t {20 66} T {20 67} t {20 68} Control_t {20 69} Control_t {20 70} Control_t {20 71} Control_t {20 72} Meta_t {20 73} Meta_T {20 74} Meta_t {20 75} Meta_T {20 76} Meta_Control_t {20 77} Meta_Control_t {20 78} Meta_Control_t {20 79} Meta_Control_t {20 80} T {20 81} t {20 82} T {20 83} t {20 84} Control_t {20 85} Control_t {20 86} Control_t {20 87} Control_t {20 88} Meta_t {20 89} Meta_T {20 90} Meta_t {20 91} Meta_T {20 92} Meta_Control_t {20 93} Meta_Control_t {20 94} Meta_Control_t {20 95} Meta_Control_t {20 96} T {20 97} t {20 98} T {20 99} t {20 100} Control_t {20 101} Control_t {20 102} Control_t {20 103} Control_t {20 104} Meta_t {20 105} Meta_T {20 106} Meta_t {20 107} Meta_T {20 108} Meta_Control_t {20 109} Meta_Control_t {20 110} Meta_Control_t {20 111} Meta_Control_t {20 112} T {20 113} t {20 114} T {20 115} t {20 116} Control_t {20 117} Control_t {20 118} Control_t {20 119} Control_t {20 120} Meta_t {20 121} Meta_T {20 122} Meta_t {20 123} Meta_T {20 124} Meta_Control_t {20 125} Meta_Control_t {20 126} Meta_Control_t {20 127} Meta_Control_t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} Control_y {21 5} Control_y {21 6} Control_y {21 7} Control_y {21 8} Meta_y {21 9} Meta_Y {21 10} Meta_y {21 11} Meta_Y {21 12} Meta_Control_y {21 13} Meta_Control_y {21 14} Meta_Control_y {21 15} Meta_Control_y {21 16} y {21 17} Y {21 18} y {21 19} Y {21 20} Control_y {21 21} Control_y {21 22} Control_y {21 23} Control_y {21 24} Meta_y {21 25} Meta_Y {21 26} Meta_y {21 27} Meta_Y {21 28} Meta_Control_y {21 29} Meta_Control_y {21 30} Meta_Control_y {21 31} Meta_Control_y {21 32} y {21 33} Y {21 34} y {21 35} Y {21 36} Control_y {21 37} Control_y {21 38} Control_y {21 39} Control_y {21 40} Meta_y {21 41} Meta_Y {21 42} Meta_y {21 43} Meta_Y {21 44} Meta_Control_y {21 45} Meta_Control_y {21 46} Meta_Control_y {21 47} Meta_Control_y {21 48} y {21 49} Y {21 50} y {21 51} Y {21 52} Control_y {21 53} Control_y {21 54} Control_y {21 55} Control_y {21 56} Meta_y {21 57} Meta_Y {21 58} Meta_y {21 59} Meta_Y {21 60} Meta_Control_y {21 61} Meta_Control_y {21 62} Meta_Control_y {21 63} Meta_Control_y {21 64} Y {21 65} y {21 66} Y {21 67} y {21 68} Control_y {21 69} Control_y {21 70} Control_y {21 71} Control_y {21 72} Meta_y {21 73} Meta_Y {21 74} Meta_y {21 75} Meta_Y {21 76} Meta_Control_y {21 77} Meta_Control_y {21 78} Meta_Control_y {21 79} Meta_Control_y {21 80} Y {21 81} y {21 82} Y {21 83} y {21 84} Control_y {21 85} Control_y {21 86} Control_y {21 87} Control_y {21 88} Meta_y {21 89} Meta_Y {21 90} Meta_y {21 91} Meta_Y {21 92} Meta_Control_y {21 93} Meta_Control_y {21 94} Meta_Control_y {21 95} Meta_Control_y {21 96} Y {21 97} y {21 98} Y {21 99} y {21 100} Control_y {21 101} Control_y {21 102} Control_y {21 103} Control_y {21 104} Meta_y {21 105} Meta_Y {21 106} Meta_y {21 107} Meta_Y {21 108} Meta_Control_y {21 109} Meta_Control_y {21 110} Meta_Control_y {21 111} Meta_Control_y {21 112} Y {21 113} y {21 114} Y {21 115} y {21 116} Control_y {21 117} Control_y {21 118} Control_y {21 119} Control_y {21 120} Meta_y {21 121} Meta_Y {21 122} Meta_y {21 123} Meta_Y {21 124} Meta_Control_y {21 125} Meta_Control_y {21 126} Meta_Control_y {21 127} Meta_Control_y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} Control_u {22 5} Control_u {22 6} Control_u {22 7} Control_u {22 8} Meta_u {22 9} Meta_U {22 10} Meta_u {22 11} Meta_U {22 12} Meta_Control_u {22 13} Meta_Control_u {22 14} Meta_Control_u {22 15} Meta_Control_u {22 16} u {22 17} U {22 18} u {22 19} U {22 20} Control_u {22 21} Control_u {22 22} Control_u {22 23} Control_u {22 24} Meta_u {22 25} Meta_U {22 26} Meta_u {22 27} Meta_U {22 28} Meta_Control_u {22 29} Meta_Control_u {22 30} Meta_Control_u {22 31} Meta_Control_u {22 32} u {22 33} U {22 34} u {22 35} U {22 36} Control_u {22 37} Control_u {22 38} Control_u {22 39} Control_u {22 40} Meta_u {22 41} Meta_U {22 42} Meta_u {22 43} Meta_U {22 44} Meta_Control_u {22 45} Meta_Control_u {22 46} Meta_Control_u {22 47} Meta_Control_u {22 48} u {22 49} U {22 50} u {22 51} U {22 52} Control_u {22 53} Control_u {22 54} Control_u {22 55} Control_u {22 56} Meta_u {22 57} Meta_U {22 58} Meta_u {22 59} Meta_U {22 60} Meta_Control_u {22 61} Meta_Control_u {22 62} Meta_Control_u {22 63} Meta_Control_u {22 64} U {22 65} u {22 66} U {22 67} u {22 68} Control_u {22 69} Control_u {22 70} Control_u {22 71} Control_u {22 72} Meta_u {22 73} Meta_U {22 74} Meta_u {22 75} Meta_U {22 76} Meta_Control_u {22 77} Meta_Control_u {22 78} Meta_Control_u {22 79} Meta_Control_u {22 80} U {22 81} u {22 82} U {22 83} u {22 84} Control_u {22 85} Control_u {22 86} Control_u {22 87} Control_u {22 88} Meta_u {22 89} Meta_U {22 90} Meta_u {22 91} Meta_U {22 92} Meta_Control_u {22 93} Meta_Control_u {22 94} Meta_Control_u {22 95} Meta_Control_u {22 96} U {22 97} u {22 98} U {22 99} u {22 100} Control_u {22 101} Control_u {22 102} Control_u {22 103} Control_u {22 104} Meta_u {22 105} Meta_U {22 106} Meta_u {22 107} Meta_U {22 108} Meta_Control_u {22 109} Meta_Control_u {22 110} Meta_Control_u {22 111} Meta_Control_u {22 112} U {22 113} u {22 114} U {22 115} u {22 116} Control_u {22 117} Control_u {22 118} Control_u {22 119} Control_u {22 120} Meta_u {22 121} Meta_U {22 122} Meta_u {22 123} Meta_U {22 124} Meta_Control_u {22 125} Meta_Control_u {22 126} Meta_Control_u {22 127} Meta_Control_u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} Tab {23 5} Tab {23 6} Tab {23 7} Tab {23 8} Meta_i {23 9} Meta_I {23 10} Meta_i {23 11} Meta_I {23 12} Meta_Tab {23 13} Meta_Tab {23 14} Meta_Tab {23 15} Meta_Tab {23 16} i {23 17} I {23 18} i {23 19} I {23 20} Tab {23 21} Tab {23 22} Tab {23 23} Tab {23 24} Meta_i {23 25} Meta_I {23 26} Meta_i {23 27} Meta_I {23 28} Meta_Tab {23 29} Meta_Tab {23 30} Meta_Tab {23 31} Meta_Tab {23 32} i {23 33} I {23 34} i {23 35} I {23 36} Tab {23 37} Tab {23 38} Tab {23 39} Tab {23 40} Meta_i {23 41} Meta_I {23 42} Meta_i {23 43} Meta_I {23 44} Meta_Tab {23 45} Meta_Tab {23 46} Meta_Tab {23 47} Meta_Tab {23 48} i {23 49} I {23 50} i {23 51} I {23 52} Tab {23 53} Tab {23 54} Tab {23 55} Tab {23 56} Meta_i {23 57} Meta_I {23 58} Meta_i {23 59} Meta_I {23 60} Meta_Tab {23 61} Meta_Tab {23 62} Meta_Tab {23 63} Meta_Tab {23 64} I {23 65} i {23 66} I {23 67} i {23 68} Tab {23 69} Tab {23 70} Tab {23 71} Tab {23 72} Meta_i {23 73} Meta_I {23 74} Meta_i {23 75} Meta_I {23 76} Meta_Tab {23 77} Meta_Tab {23 78} Meta_Tab {23 79} Meta_Tab {23 80} I {23 81} i {23 82} I {23 83} i {23 84} Tab {23 85} Tab {23 86} Tab {23 87} Tab {23 88} Meta_i {23 89} Meta_I {23 90} Meta_i {23 91} Meta_I {23 92} Meta_Tab {23 93} Meta_Tab {23 94} Meta_Tab {23 95} Meta_Tab {23 96} I {23 97} i {23 98} I {23 99} i {23 100} Tab {23 101} Tab {23 102} Tab {23 103} Tab {23 104} Meta_i {23 105} Meta_I {23 106} Meta_i {23 107} Meta_I {23 108} Meta_Tab {23 109} Meta_Tab {23 110} Meta_Tab {23 111} Meta_Tab {23 112} I {23 113} i {23 114} I {23 115} i {23 116} Tab {23 117} Tab {23 118} Tab {23 119} Tab {23 120} Meta_i {23 121} Meta_I {23 122} Meta_i {23 123} Meta_I {23 124} Meta_Tab {23 125} Meta_Tab {23 126} Meta_Tab {23 127} Meta_Tab {24 0} o {24 1} O {24 2} o {24 3} O {24 4} Control_o {24 5} Control_o {24 6} Control_o {24 7} Control_o {24 8} Meta_o {24 9} Meta_O {24 10} Meta_o {24 11} Meta_O {24 12} Meta_Control_o {24 13} Meta_Control_o {24 14} Meta_Control_o {24 15} Meta_Control_o {24 16} o {24 17} O {24 18} o {24 19} O {24 20} Control_o {24 21} Control_o {24 22} Control_o {24 23} Control_o {24 24} Meta_o {24 25} Meta_O {24 26} Meta_o {24 27} Meta_O {24 28} Meta_Control_o {24 29} Meta_Control_o {24 30} Meta_Control_o {24 31} Meta_Control_o {24 32} o {24 33} O {24 34} o {24 35} O {24 36} Control_o {24 37} Control_o {24 38} Control_o {24 39} Control_o {24 40} Meta_o {24 41} Meta_O {24 42} Meta_o {24 43} Meta_O {24 44} Meta_Control_o {24 45} Meta_Control_o {24 46} Meta_Control_o {24 47} Meta_Control_o {24 48} o {24 49} O {24 50} o {24 51} O {24 52} Control_o {24 53} Control_o {24 54} Control_o {24 55} Control_o {24 56} Meta_o {24 57} Meta_O {24 58} Meta_o {24 59} Meta_O {24 60} Meta_Control_o {24 61} Meta_Control_o {24 62} Meta_Control_o {24 63} Meta_Control_o {24 64} O {24 65} o {24 66} O {24 67} o {24 68} Control_o {24 69} Control_o {24 70} Control_o {24 71} Control_o {24 72} Meta_o {24 73} Meta_O {24 74} Meta_o {24 75} Meta_O {24 76} Meta_Control_o {24 77} Meta_Control_o {24 78} Meta_Control_o {24 79} Meta_Control_o {24 80} O {24 81} o {24 82} O {24 83} o {24 84} Control_o {24 85} Control_o {24 86} Control_o {24 87} Control_o {24 88} Meta_o {24 89} Meta_O {24 90} Meta_o {24 91} Meta_O {24 92} Meta_Control_o {24 93} Meta_Control_o {24 94} Meta_Control_o {24 95} Meta_Control_o {24 96} O {24 97} o {24 98} O {24 99} o {24 100} Control_o {24 101} Control_o {24 102} Control_o {24 103} Control_o {24 104} Meta_o {24 105} Meta_O {24 106} Meta_o {24 107} Meta_O {24 108} Meta_Control_o {24 109} Meta_Control_o {24 110} Meta_Control_o {24 111} Meta_Control_o {24 112} O {24 113} o {24 114} O {24 115} o {24 116} Control_o {24 117} Control_o {24 118} Control_o {24 119} Control_o {24 120} Meta_o {24 121} Meta_O {24 122} Meta_o {24 123} Meta_O {24 124} Meta_Control_o {24 125} Meta_Control_o {24 126} Meta_Control_o {24 127} Meta_Control_o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} Control_p {25 5} Control_p {25 6} Control_p {25 7} Control_p {25 8} Meta_p {25 9} Meta_P {25 10} Meta_p {25 11} Meta_P {25 12} Meta_Control_p {25 13} Meta_Control_p {25 14} Meta_Control_p {25 15} Meta_Control_p {25 16} p {25 17} P {25 18} p {25 19} P {25 20} Control_p {25 21} Control_p {25 22} Control_p {25 23} Control_p {25 24} Meta_p {25 25} Meta_P {25 26} Meta_p {25 27} Meta_P {25 28} Meta_Control_p {25 29} Meta_Control_p {25 30} Meta_Control_p {25 31} Meta_Control_p {25 32} p {25 33} P {25 34} p {25 35} P {25 36} Control_p {25 37} Control_p {25 38} Control_p {25 39} Control_p {25 40} Meta_p {25 41} Meta_P {25 42} Meta_p {25 43} Meta_P {25 44} Meta_Control_p {25 45} Meta_Control_p {25 46} Meta_Control_p {25 47} Meta_Control_p {25 48} p {25 49} P {25 50} p {25 51} P {25 52} Control_p {25 53} Control_p {25 54} Control_p {25 55} Control_p {25 56} Meta_p {25 57} Meta_P {25 58} Meta_p {25 59} Meta_P {25 60} Meta_Control_p {25 61} Meta_Control_p {25 62} Meta_Control_p {25 63} Meta_Control_p {25 64} P {25 65} p {25 66} P {25 67} p {25 68} Control_p {25 69} Control_p {25 70} Control_p {25 71} Control_p {25 72} Meta_p {25 73} Meta_P {25 74} Meta_p {25 75} Meta_P {25 76} Meta_Control_p {25 77} Meta_Control_p {25 78} Meta_Control_p {25 79} Meta_Control_p {25 80} P {25 81} p {25 82} P {25 83} p {25 84} Control_p {25 85} Control_p {25 86} Control_p {25 87} Control_p {25 88} Meta_p {25 89} Meta_P {25 90} Meta_p {25 91} Meta_P {25 92} Meta_Control_p {25 93} Meta_Control_p {25 94} Meta_Control_p {25 95} Meta_Control_p {25 96} P {25 97} p {25 98} P {25 99} p {25 100} Control_p {25 101} Control_p {25 102} Control_p {25 103} Control_p {25 104} Meta_p {25 105} Meta_P {25 106} Meta_p {25 107} Meta_P {25 108} Meta_Control_p {25 109} Meta_Control_p {25 110} Meta_Control_p {25 111} Meta_Control_p {25 112} P {25 113} p {25 114} P {25 115} p {25 116} Control_p {25 117} Control_p {25 118} Control_p {25 119} Control_p {25 120} Meta_p {25 121} Meta_P {25 122} Meta_p {25 123} Meta_P {25 124} Meta_Control_p {25 125} Meta_Control_p {25 126} Meta_Control_p {25 127} Meta_Control_p {26 0} bracketleft {26 1} braceleft {26 2} bracketleft {26 3} braceleft {26 4} Escape {26 5} Escape {26 6} Escape {26 7} Escape {26 8} Meta_bracketleft {26 9} Meta_braceleft {26 10} Meta_bracketleft {26 11} Meta_braceleft {26 12} Meta_Escape {26 13} Meta_Escape {26 14} Meta_Escape {26 15} Meta_Escape {26 16} bracketleft {26 17} braceleft {26 18} bracketleft {26 19} braceleft {26 20} Escape {26 21} Escape {26 22} Escape {26 23} Escape {26 24} Meta_bracketleft {26 25} Meta_braceleft {26 26} Meta_bracketleft {26 27} Meta_braceleft {26 28} Meta_Escape {26 29} Meta_Escape {26 30} Meta_Escape {26 31} Meta_Escape {26 32} bracketleft {26 33} braceleft {26 34} bracketleft {26 35} braceleft {26 36} Escape {26 37} Escape {26 38} Escape {26 39} Escape {26 40} Meta_bracketleft {26 41} Meta_braceleft {26 42} Meta_bracketleft {26 43} Meta_braceleft {26 44} Meta_Escape {26 45} Meta_Escape {26 46} Meta_Escape {26 47} Meta_Escape {26 48} bracketleft {26 49} braceleft {26 50} bracketleft {26 51} braceleft {26 52} Escape {26 53} Escape {26 54} Escape {26 55} Escape {26 56} Meta_bracketleft {26 57} Meta_braceleft {26 58} Meta_bracketleft {26 59} Meta_braceleft {26 60} Meta_Escape {26 61} Meta_Escape {26 62} Meta_Escape {26 63} Meta_Escape {26 64} bracketleft {26 65} braceleft {26 66} bracketleft {26 67} braceleft {26 68} Escape {26 69} Escape {26 70} Escape {26 71} Escape {26 72} Meta_bracketleft {26 73} Meta_braceleft {26 74} Meta_bracketleft {26 75} Meta_braceleft {26 76} Meta_Escape {26 77} Meta_Escape {26 78} Meta_Escape {26 79} Meta_Escape {26 80} bracketleft {26 81} braceleft {26 82} bracketleft {26 83} braceleft {26 84} Escape {26 85} Escape {26 86} Escape {26 87} Escape {26 88} Meta_bracketleft {26 89} Meta_braceleft {26 90} Meta_bracketleft {26 91} Meta_braceleft {26 92} Meta_Escape {26 93} Meta_Escape {26 94} Meta_Escape {26 95} Meta_Escape {26 96} bracketleft {26 97} braceleft {26 98} bracketleft {26 99} braceleft {26 100} Escape {26 101} Escape {26 102} Escape {26 103} Escape {26 104} Meta_bracketleft {26 105} Meta_braceleft {26 106} Meta_bracketleft {26 107} Meta_braceleft {26 108} Meta_Escape {26 109} Meta_Escape {26 110} Meta_Escape {26 111} Meta_Escape {26 112} bracketleft {26 113} braceleft {26 114} bracketleft {26 115} braceleft {26 116} Escape {26 117} Escape {26 118} Escape {26 119} Escape {26 120} Meta_bracketleft {26 121} Meta_braceleft {26 122} Meta_bracketleft {26 123} Meta_braceleft {26 124} Meta_Escape {26 125} Meta_Escape {26 126} Meta_Escape {26 127} Meta_Escape {27 0} bracketright {27 1} braceright {27 2} bracketright {27 3} braceright {27 4} Control_bracketright {27 5} Control_bracketright {27 6} Control_bracketright {27 7} Control_bracketright {27 8} Meta_bracketright {27 9} Meta_braceright {27 10} Meta_bracketright {27 11} Meta_braceright {27 12} Meta_Control_bracketright {27 13} Meta_Control_bracketright {27 14} Meta_Control_bracketright {27 15} Meta_Control_bracketright {27 16} bracketright {27 17} braceright {27 18} bracketright {27 19} braceright {27 20} Control_bracketright {27 21} Control_bracketright {27 22} Control_bracketright {27 23} Control_bracketright {27 24} Meta_bracketright {27 25} Meta_braceright {27 26} Meta_bracketright {27 27} Meta_braceright {27 28} Meta_Control_bracketright {27 29} Meta_Control_bracketright {27 30} Meta_Control_bracketright {27 31} Meta_Control_bracketright {27 32} bracketright {27 33} braceright {27 34} bracketright {27 35} braceright {27 36} Control_bracketright {27 37} Control_bracketright {27 38} Control_bracketright {27 39} Control_bracketright {27 40} Meta_bracketright {27 41} Meta_braceright {27 42} Meta_bracketright {27 43} Meta_braceright {27 44} Meta_Control_bracketright {27 45} Meta_Control_bracketright {27 46} Meta_Control_bracketright {27 47} Meta_Control_bracketright {27 48} bracketright {27 49} braceright {27 50} bracketright {27 51} braceright {27 52} Control_bracketright {27 53} Control_bracketright {27 54} Control_bracketright {27 55} Control_bracketright {27 56} Meta_bracketright {27 57} Meta_braceright {27 58} Meta_bracketright {27 59} Meta_braceright {27 60} Meta_Control_bracketright {27 61} Meta_Control_bracketright {27 62} Meta_Control_bracketright {27 63} Meta_Control_bracketright {27 64} bracketright {27 65} braceright {27 66} bracketright {27 67} braceright {27 68} Control_bracketright {27 69} Control_bracketright {27 70} Control_bracketright {27 71} Control_bracketright {27 72} Meta_bracketright {27 73} Meta_braceright {27 74} Meta_bracketright {27 75} Meta_braceright {27 76} Meta_Control_bracketright {27 77} Meta_Control_bracketright {27 78} Meta_Control_bracketright {27 79} Meta_Control_bracketright {27 80} bracketright {27 81} braceright {27 82} bracketright {27 83} braceright {27 84} Control_bracketright {27 85} Control_bracketright {27 86} Control_bracketright {27 87} Control_bracketright {27 88} Meta_bracketright {27 89} Meta_braceright {27 90} Meta_bracketright {27 91} Meta_braceright {27 92} Meta_Control_bracketright {27 93} Meta_Control_bracketright {27 94} Meta_Control_bracketright {27 95} Meta_Control_bracketright {27 96} bracketright {27 97} braceright {27 98} bracketright {27 99} braceright {27 100} Control_bracketright {27 101} Control_bracketright {27 102} Control_bracketright {27 103} Control_bracketright {27 104} Meta_bracketright {27 105} Meta_braceright {27 106} Meta_bracketright {27 107} Meta_braceright {27 108} Meta_Control_bracketright {27 109} Meta_Control_bracketright {27 110} Meta_Control_bracketright {27 111} Meta_Control_bracketright {27 112} bracketright {27 113} braceright {27 114} bracketright {27 115} braceright {27 116} Control_bracketright {27 117} Control_bracketright {27 118} Control_bracketright {27 119} Control_bracketright {27 120} Meta_bracketright {27 121} Meta_braceright {27 122} Meta_bracketright {27 123} Meta_braceright {27 124} Meta_Control_bracketright {27 125} Meta_Control_bracketright {27 126} Meta_Control_bracketright {27 127} Meta_Control_bracketright {28 0} Return {28 1} Return {28 2} Return {28 3} Return {28 4} Control_m {28 5} Control_m {28 6} Control_m {28 7} Control_m {28 8} Meta_Control_m {28 9} Meta_Control_m {28 10} Meta_Control_m {28 11} Meta_Control_m {28 12} Meta_Control_m {28 13} Meta_Control_m {28 14} Meta_Control_m {28 15} Meta_Control_m {28 16} Return {28 17} Return {28 18} Return {28 19} Return {28 20} Control_m {28 21} Control_m {28 22} Control_m {28 23} Control_m {28 24} Meta_Control_m {28 25} Meta_Control_m {28 26} Meta_Control_m {28 27} Meta_Control_m {28 28} Meta_Control_m {28 29} Meta_Control_m {28 30} Meta_Control_m {28 31} Meta_Control_m {28 32} Return {28 33} Return {28 34} Return {28 35} Return {28 36} Control_m {28 37} Control_m {28 38} Control_m {28 39} Control_m {28 40} Meta_Control_m {28 41} Meta_Control_m {28 42} Meta_Control_m {28 43} Meta_Control_m {28 44} Meta_Control_m {28 45} Meta_Control_m {28 46} Meta_Control_m {28 47} Meta_Control_m {28 48} Return {28 49} Return {28 50} Return {28 51} Return {28 52} Control_m {28 53} Control_m {28 54} Control_m {28 55} Control_m {28 56} Meta_Control_m {28 57} Meta_Control_m {28 58} Meta_Control_m {28 59} Meta_Control_m {28 60} Meta_Control_m {28 61} Meta_Control_m {28 62} Meta_Control_m {28 63} Meta_Control_m {28 64} Return {28 65} Return {28 66} Return {28 67} Return {28 68} Control_m {28 69} Control_m {28 70} Control_m {28 71} Control_m {28 72} Meta_Control_m {28 73} Meta_Control_m {28 74} Meta_Control_m {28 75} Meta_Control_m {28 76} Meta_Control_m {28 77} Meta_Control_m {28 78} Meta_Control_m {28 79} Meta_Control_m {28 80} Return {28 81} Return {28 82} Return {28 83} Return {28 84} Control_m {28 85} Control_m {28 86} Control_m {28 87} Control_m {28 88} Meta_Control_m {28 89} Meta_Control_m {28 90} Meta_Control_m {28 91} Meta_Control_m {28 92} Meta_Control_m {28 93} Meta_Control_m {28 94} Meta_Control_m {28 95} Meta_Control_m {28 96} Return {28 97} Return {28 98} Return {28 99} Return {28 100} Control_m {28 101} Control_m {28 102} Control_m {28 103} Control_m {28 104} Meta_Control_m {28 105} Meta_Control_m {28 106} Meta_Control_m {28 107} Meta_Control_m {28 108} Meta_Control_m {28 109} Meta_Control_m {28 110} Meta_Control_m {28 111} Meta_Control_m {28 112} Return {28 113} Return {28 114} Return {28 115} Return {28 116} Control_m {28 117} Control_m {28 118} Control_m {28 119} Control_m {28 120} Meta_Control_m {28 121} Meta_Control_m {28 122} Meta_Control_m {28 123} Meta_Control_m {28 124} Meta_Control_m {28 125} Meta_Control_m {28 126} Meta_Control_m {28 127} Meta_Control_m {29 0} Control {29 1} Control {29 2} Control {29 3} Control {29 4} Control {29 5} Control {29 6} Control {29 7} Control {29 8} Control {29 9} Control {29 10} Control {29 11} Control {29 12} Control {29 13} Control {29 14} Control {29 15} Control {29 16} Control {29 17} Control {29 18} Control {29 19} Control {29 20} Control {29 21} Control {29 22} Control {29 23} Control {29 24} Control {29 25} Control {29 26} Control {29 27} Control {29 28} Control {29 29} Control {29 30} Control {29 31} Control {29 32} Control {29 33} Control {29 34} Control {29 35} Control {29 36} Control {29 37} Control {29 38} Control {29 39} Control {29 40} Control {29 41} Control {29 42} Control {29 43} Control {29 44} Control {29 45} Control {29 46} Control {29 47} Control {29 48} Control {29 49} Control {29 50} Control {29 51} Control {29 52} Control {29 53} Control {29 54} Control {29 55} Control {29 56} Control {29 57} Control {29 58} Control {29 59} Control {29 60} Control {29 61} Control {29 62} Control {29 63} Control {29 64} Control {29 65} Control {29 66} Control {29 67} Control {29 68} Control {29 69} Control {29 70} Control {29 71} Control {29 72} Control {29 73} Control {29 74} Control {29 75} Control {29 76} Control {29 77} Control {29 78} Control {29 79} Control {29 80} Control {29 81} Control {29 82} Control {29 83} Control {29 84} Control {29 85} Control {29 86} Control {29 87} Control {29 88} Control {29 89} Control {29 90} Control {29 91} Control {29 92} Control {29 93} Control {29 94} Control {29 95} Control {29 96} Control {29 97} Control {29 98} Control {29 99} Control {29 100} Control {29 101} Control {29 102} Control {29 103} Control {29 104} Control {29 105} Control {29 106} Control {29 107} Control {29 108} Control {29 109} Control {29 110} Control {29 111} Control {29 112} Control {29 113} Control {29 114} Control {29 115} Control {29 116} Control {29 117} Control {29 118} Control {29 119} Control {29 120} Control {29 121} Control {29 122} Control {29 123} Control {29 124} Control {29 125} Control {29 126} Control {29 127} Control {30 0} a {30 1} A {30 2} a {30 3} A {30 4} Control_a {30 5} Control_a {30 6} Control_a {30 7} Control_a {30 8} Meta_a {30 9} Meta_A {30 10} Meta_a {30 11} Meta_A {30 12} Meta_Control_a {30 13} Meta_Control_a {30 14} Meta_Control_a {30 15} Meta_Control_a {30 16} a {30 17} A {30 18} a {30 19} A {30 20} Control_a {30 21} Control_a {30 22} Control_a {30 23} Control_a {30 24} Meta_a {30 25} Meta_A {30 26} Meta_a {30 27} Meta_A {30 28} Meta_Control_a {30 29} Meta_Control_a {30 30} Meta_Control_a {30 31} Meta_Control_a {30 32} a {30 33} A {30 34} a {30 35} A {30 36} Control_a {30 37} Control_a {30 38} Control_a {30 39} Control_a {30 40} Meta_a {30 41} Meta_A {30 42} Meta_a {30 43} Meta_A {30 44} Meta_Control_a {30 45} Meta_Control_a {30 46} Meta_Control_a {30 47} Meta_Control_a {30 48} a {30 49} A {30 50} a {30 51} A {30 52} Control_a {30 53} Control_a {30 54} Control_a {30 55} Control_a {30 56} Meta_a {30 57} Meta_A {30 58} Meta_a {30 59} Meta_A {30 60} Meta_Control_a {30 61} Meta_Control_a {30 62} Meta_Control_a {30 63} Meta_Control_a {30 64} A {30 65} a {30 66} A {30 67} a {30 68} Control_a {30 69} Control_a {30 70} Control_a {30 71} Control_a {30 72} Meta_a {30 73} Meta_A {30 74} Meta_a {30 75} Meta_A {30 76} Meta_Control_a {30 77} Meta_Control_a {30 78} Meta_Control_a {30 79} Meta_Control_a {30 80} A {30 81} a {30 82} A {30 83} a {30 84} Control_a {30 85} Control_a {30 86} Control_a {30 87} Control_a {30 88} Meta_a {30 89} Meta_A {30 90} Meta_a {30 91} Meta_A {30 92} Meta_Control_a {30 93} Meta_Control_a {30 94} Meta_Control_a {30 95} Meta_Control_a {30 96} A {30 97} a {30 98} A {30 99} a {30 100} Control_a {30 101} Control_a {30 102} Control_a {30 103} Control_a {30 104} Meta_a {30 105} Meta_A {30 106} Meta_a {30 107} Meta_A {30 108} Meta_Control_a {30 109} Meta_Control_a {30 110} Meta_Control_a {30 111} Meta_Control_a {30 112} A {30 113} a {30 114} A {30 115} a {30 116} Control_a {30 117} Control_a {30 118} Control_a {30 119} Control_a {30 120} Meta_a {30 121} Meta_A {30 122} Meta_a {30 123} Meta_A {30 124} Meta_Control_a {30 125} Meta_Control_a {30 126} Meta_Control_a {30 127} Meta_Control_a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} Control_s {31 5} Control_s {31 6} Control_s {31 7} Control_s {31 8} Meta_s {31 9} Meta_S {31 10} Meta_s {31 11} Meta_S {31 12} Meta_Control_s {31 13} Meta_Control_s {31 14} Meta_Control_s {31 15} Meta_Control_s {31 16} s {31 17} S {31 18} s {31 19} S {31 20} Control_s {31 21} Control_s {31 22} Control_s {31 23} Control_s {31 24} Meta_s {31 25} Meta_S {31 26} Meta_s {31 27} Meta_S {31 28} Meta_Control_s {31 29} Meta_Control_s {31 30} Meta_Control_s {31 31} Meta_Control_s {31 32} s {31 33} S {31 34} s {31 35} S {31 36} Control_s {31 37} Control_s {31 38} Control_s {31 39} Control_s {31 40} Meta_s {31 41} Meta_S {31 42} Meta_s {31 43} Meta_S {31 44} Meta_Control_s {31 45} Meta_Control_s {31 46} Meta_Control_s {31 47} Meta_Control_s {31 48} s {31 49} S {31 50} s {31 51} S {31 52} Control_s {31 53} Control_s {31 54} Control_s {31 55} Control_s {31 56} Meta_s {31 57} Meta_S {31 58} Meta_s {31 59} Meta_S {31 60} Meta_Control_s {31 61} Meta_Control_s {31 62} Meta_Control_s {31 63} Meta_Control_s {31 64} S {31 65} s {31 66} S {31 67} s {31 68} Control_s {31 69} Control_s {31 70} Control_s {31 71} Control_s {31 72} Meta_s {31 73} Meta_S {31 74} Meta_s {31 75} Meta_S {31 76} Meta_Control_s {31 77} Meta_Control_s {31 78} Meta_Control_s {31 79} Meta_Control_s {31 80} S {31 81} s {31 82} S {31 83} s {31 84} Control_s {31 85} Control_s {31 86} Control_s {31 87} Control_s {31 88} Meta_s {31 89} Meta_S {31 90} Meta_s {31 91} Meta_S {31 92} Meta_Control_s {31 93} Meta_Control_s {31 94} Meta_Control_s {31 95} Meta_Control_s {31 96} S {31 97} s {31 98} S {31 99} s {31 100} Control_s {31 101} Control_s {31 102} Control_s {31 103} Control_s {31 104} Meta_s {31 105} Meta_S {31 106} Meta_s {31 107} Meta_S {31 108} Meta_Control_s {31 109} Meta_Control_s {31 110} Meta_Control_s {31 111} Meta_Control_s {31 112} S {31 113} s {31 114} S {31 115} s {31 116} Control_s {31 117} Control_s {31 118} Control_s {31 119} Control_s {31 120} Meta_s {31 121} Meta_S {31 122} Meta_s {31 123} Meta_S {31 124} Meta_Control_s {31 125} Meta_Control_s {31 126} Meta_Control_s {31 127} Meta_Control_s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} Control_d {32 5} Control_d {32 6} Control_d {32 7} Control_d {32 8} Meta_d {32 9} Meta_D {32 10} Meta_d {32 11} Meta_D {32 12} Meta_Control_d {32 13} Meta_Control_d {32 14} Meta_Control_d {32 15} Meta_Control_d {32 16} d {32 17} D {32 18} d {32 19} D {32 20} Control_d {32 21} Control_d {32 22} Control_d {32 23} Control_d {32 24} Meta_d {32 25} Meta_D {32 26} Meta_d {32 27} Meta_D {32 28} Meta_Control_d {32 29} Meta_Control_d {32 30} Meta_Control_d {32 31} Meta_Control_d {32 32} d {32 33} D {32 34} d {32 35} D {32 36} Control_d {32 37} Control_d {32 38} Control_d {32 39} Control_d {32 40} Meta_d {32 41} Meta_D {32 42} Meta_d {32 43} Meta_D {32 44} Meta_Control_d {32 45} Meta_Control_d {32 46} Meta_Control_d {32 47} Meta_Control_d {32 48} d {32 49} D {32 50} d {32 51} D {32 52} Control_d {32 53} Control_d {32 54} Control_d {32 55} Control_d {32 56} Meta_d {32 57} Meta_D {32 58} Meta_d {32 59} Meta_D {32 60} Meta_Control_d {32 61} Meta_Control_d {32 62} Meta_Control_d {32 63} Meta_Control_d {32 64} D {32 65} d {32 66} D {32 67} d {32 68} Control_d {32 69} Control_d {32 70} Control_d {32 71} Control_d {32 72} Meta_d {32 73} Meta_D {32 74} Meta_d {32 75} Meta_D {32 76} Meta_Control_d {32 77} Meta_Control_d {32 78} Meta_Control_d {32 79} Meta_Control_d {32 80} D {32 81} d {32 82} D {32 83} d {32 84} Control_d {32 85} Control_d {32 86} Control_d {32 87} Control_d {32 88} Meta_d {32 89} Meta_D {32 90} Meta_d {32 91} Meta_D {32 92} Meta_Control_d {32 93} Meta_Control_d {32 94} Meta_Control_d {32 95} Meta_Control_d {32 96} D {32 97} d {32 98} D {32 99} d {32 100} Control_d {32 101} Control_d {32 102} Control_d {32 103} Control_d {32 104} Meta_d {32 105} Meta_D {32 106} Meta_d {32 107} Meta_D {32 108} Meta_Control_d {32 109} Meta_Control_d {32 110} Meta_Control_d {32 111} Meta_Control_d {32 112} D {32 113} d {32 114} D {32 115} d {32 116} Control_d {32 117} Control_d {32 118} Control_d {32 119} Control_d {32 120} Meta_d {32 121} Meta_D {32 122} Meta_d {32 123} Meta_D {32 124} Meta_Control_d {32 125} Meta_Control_d {32 126} Meta_Control_d {32 127} Meta_Control_d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} Control_f {33 5} Control_f {33 6} Control_f {33 7} Control_f {33 8} Meta_f {33 9} Meta_F {33 10} Meta_f {33 11} Meta_F {33 12} Meta_Control_f {33 13} Meta_Control_f {33 14} Meta_Control_f {33 15} Meta_Control_f {33 16} f {33 17} F {33 18} f {33 19} F {33 20} Control_f {33 21} Control_f {33 22} Control_f {33 23} Control_f {33 24} Meta_f {33 25} Meta_F {33 26} Meta_f {33 27} Meta_F {33 28} Meta_Control_f {33 29} Meta_Control_f {33 30} Meta_Control_f {33 31} Meta_Control_f {33 32} f {33 33} F {33 34} f {33 35} F {33 36} Control_f {33 37} Control_f {33 38} Control_f {33 39} Control_f {33 40} Meta_f {33 41} Meta_F {33 42} Meta_f {33 43} Meta_F {33 44} Meta_Control_f {33 45} Meta_Control_f {33 46} Meta_Control_f {33 47} Meta_Control_f {33 48} f {33 49} F {33 50} f {33 51} F {33 52} Control_f {33 53} Control_f {33 54} Control_f {33 55} Control_f {33 56} Meta_f {33 57} Meta_F {33 58} Meta_f {33 59} Meta_F {33 60} Meta_Control_f {33 61} Meta_Control_f {33 62} Meta_Control_f {33 63} Meta_Control_f {33 64} F {33 65} f {33 66} F {33 67} f {33 68} Control_f {33 69} Control_f {33 70} Control_f {33 71} Control_f {33 72} Meta_f {33 73} Meta_F {33 74} Meta_f {33 75} Meta_F {33 76} Meta_Control_f {33 77} Meta_Control_f {33 78} Meta_Control_f {33 79} Meta_Control_f {33 80} F {33 81} f {33 82} F {33 83} f {33 84} Control_f {33 85} Control_f {33 86} Control_f {33 87} Control_f {33 88} Meta_f {33 89} Meta_F {33 90} Meta_f {33 91} Meta_F {33 92} Meta_Control_f {33 93} Meta_Control_f {33 94} Meta_Control_f {33 95} Meta_Control_f {33 96} F {33 97} f {33 98} F {33 99} f {33 100} Control_f {33 101} Control_f {33 102} Control_f {33 103} Control_f {33 104} Meta_f {33 105} Meta_F {33 106} Meta_f {33 107} Meta_F {33 108} Meta_Control_f {33 109} Meta_Control_f {33 110} Meta_Control_f {33 111} Meta_Control_f {33 112} F {33 113} f {33 114} F {33 115} f {33 116} Control_f {33 117} Control_f {33 118} Control_f {33 119} Control_f {33 120} Meta_f {33 121} Meta_F {33 122} Meta_f {33 123} Meta_F {33 124} Meta_Control_f {33 125} Meta_Control_f {33 126} Meta_Control_f {33 127} Meta_Control_f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} Control_g {34 5} Control_g {34 6} Control_g {34 7} Control_g {34 8} Meta_g {34 9} Meta_G {34 10} Meta_g {34 11} Meta_G {34 12} Meta_Control_g {34 13} Meta_Control_g {34 14} Meta_Control_g {34 15} Meta_Control_g {34 16} g {34 17} G {34 18} g {34 19} G {34 20} Control_g {34 21} Control_g {34 22} Control_g {34 23} Control_g {34 24} Meta_g {34 25} Meta_G {34 26} Meta_g {34 27} Meta_G {34 28} Meta_Control_g {34 29} Meta_Control_g {34 30} Meta_Control_g {34 31} Meta_Control_g {34 32} g {34 33} G {34 34} g {34 35} G {34 36} Control_g {34 37} Control_g {34 38} Control_g {34 39} Control_g {34 40} Meta_g {34 41} Meta_G {34 42} Meta_g {34 43} Meta_G {34 44} Meta_Control_g {34 45} Meta_Control_g {34 46} Meta_Control_g {34 47} Meta_Control_g {34 48} g {34 49} G {34 50} g {34 51} G {34 52} Control_g {34 53} Control_g {34 54} Control_g {34 55} Control_g {34 56} Meta_g {34 57} Meta_G {34 58} Meta_g {34 59} Meta_G {34 60} Meta_Control_g {34 61} Meta_Control_g {34 62} Meta_Control_g {34 63} Meta_Control_g {34 64} G {34 65} g {34 66} G {34 67} g {34 68} Control_g {34 69} Control_g {34 70} Control_g {34 71} Control_g {34 72} Meta_g {34 73} Meta_G {34 74} Meta_g {34 75} Meta_G {34 76} Meta_Control_g {34 77} Meta_Control_g {34 78} Meta_Control_g {34 79} Meta_Control_g {34 80} G {34 81} g {34 82} G {34 83} g {34 84} Control_g {34 85} Control_g {34 86} Control_g {34 87} Control_g {34 88} Meta_g {34 89} Meta_G {34 90} Meta_g {34 91} Meta_G {34 92} Meta_Control_g {34 93} Meta_Control_g {34 94} Meta_Control_g {34 95} Meta_Control_g {34 96} G {34 97} g {34 98} G {34 99} g {34 100} Control_g {34 101} Control_g {34 102} Control_g {34 103} Control_g {34 104} Meta_g {34 105} Meta_G {34 106} Meta_g {34 107} Meta_G {34 108} Meta_Control_g {34 109} Meta_Control_g {34 110} Meta_Control_g {34 111} Meta_Control_g {34 112} G {34 113} g {34 114} G {34 115} g {34 116} Control_g {34 117} Control_g {34 118} Control_g {34 119} Control_g {34 120} Meta_g {34 121} Meta_G {34 122} Meta_g {34 123} Meta_G {34 124} Meta_Control_g {34 125} Meta_Control_g {34 126} Meta_Control_g {34 127} Meta_Control_g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} BackSpace {35 5} BackSpace {35 6} BackSpace {35 7} BackSpace {35 8} Meta_h {35 9} Meta_H {35 10} Meta_h {35 11} Meta_H {35 12} Meta_BackSpace {35 13} Meta_BackSpace {35 14} Meta_BackSpace {35 15} Meta_BackSpace {35 16} h {35 17} H {35 18} h {35 19} H {35 20} BackSpace {35 21} BackSpace {35 22} BackSpace {35 23} BackSpace {35 24} Meta_h {35 25} Meta_H {35 26} Meta_h {35 27} Meta_H {35 28} Meta_BackSpace {35 29} Meta_BackSpace {35 30} Meta_BackSpace {35 31} Meta_BackSpace {35 32} h {35 33} H {35 34} h {35 35} H {35 36} BackSpace {35 37} BackSpace {35 38} BackSpace {35 39} BackSpace {35 40} Meta_h {35 41} Meta_H {35 42} Meta_h {35 43} Meta_H {35 44} Meta_BackSpace {35 45} Meta_BackSpace {35 46} Meta_BackSpace {35 47} Meta_BackSpace {35 48} h {35 49} H {35 50} h {35 51} H {35 52} BackSpace {35 53} BackSpace {35 54} BackSpace {35 55} BackSpace {35 56} Meta_h {35 57} Meta_H {35 58} Meta_h {35 59} Meta_H {35 60} Meta_BackSpace {35 61} Meta_BackSpace {35 62} Meta_BackSpace {35 63} Meta_BackSpace {35 64} H {35 65} h {35 66} H {35 67} h {35 68} BackSpace {35 69} BackSpace {35 70} BackSpace {35 71} BackSpace {35 72} Meta_h {35 73} Meta_H {35 74} Meta_h {35 75} Meta_H {35 76} Meta_BackSpace {35 77} Meta_BackSpace {35 78} Meta_BackSpace {35 79} Meta_BackSpace {35 80} H {35 81} h {35 82} H {35 83} h {35 84} BackSpace {35 85} BackSpace {35 86} BackSpace {35 87} BackSpace {35 88} Meta_h {35 89} Meta_H {35 90} Meta_h {35 91} Meta_H {35 92} Meta_BackSpace {35 93} Meta_BackSpace {35 94} Meta_BackSpace {35 95} Meta_BackSpace {35 96} H {35 97} h {35 98} H {35 99} h {35 100} BackSpace {35 101} BackSpace {35 102} BackSpace {35 103} BackSpace {35 104} Meta_h {35 105} Meta_H {35 106} Meta_h {35 107} Meta_H {35 108} Meta_BackSpace {35 109} Meta_BackSpace {35 110} Meta_BackSpace {35 111} Meta_BackSpace {35 112} H {35 113} h {35 114} H {35 115} h {35 116} BackSpace {35 117} BackSpace {35 118} BackSpace {35 119} BackSpace {35 120} Meta_h {35 121} Meta_H {35 122} Meta_h {35 123} Meta_H {35 124} Meta_BackSpace {35 125} Meta_BackSpace {35 126} Meta_BackSpace {35 127} Meta_BackSpace {36 0} j {36 1} J {36 2} j {36 3} J {36 4} Linefeed {36 5} Linefeed {36 6} Linefeed {36 7} Linefeed {36 8} Meta_j {36 9} Meta_J {36 10} Meta_j {36 11} Meta_J {36 12} Meta_Linefeed {36 13} Meta_Linefeed {36 14} Meta_Linefeed {36 15} Meta_Linefeed {36 16} j {36 17} J {36 18} j {36 19} J {36 20} Linefeed {36 21} Linefeed {36 22} Linefeed {36 23} Linefeed {36 24} Meta_j {36 25} Meta_J {36 26} Meta_j {36 27} Meta_J {36 28} Meta_Linefeed {36 29} Meta_Linefeed {36 30} Meta_Linefeed {36 31} Meta_Linefeed {36 32} j {36 33} J {36 34} j {36 35} J {36 36} Linefeed {36 37} Linefeed {36 38} Linefeed {36 39} Linefeed {36 40} Meta_j {36 41} Meta_J {36 42} Meta_j {36 43} Meta_J {36 44} Meta_Linefeed {36 45} Meta_Linefeed {36 46} Meta_Linefeed {36 47} Meta_Linefeed {36 48} j {36 49} J {36 50} j {36 51} J {36 52} Linefeed {36 53} Linefeed {36 54} Linefeed {36 55} Linefeed {36 56} Meta_j {36 57} Meta_J {36 58} Meta_j {36 59} Meta_J {36 60} Meta_Linefeed {36 61} Meta_Linefeed {36 62} Meta_Linefeed {36 63} Meta_Linefeed {36 64} J {36 65} j {36 66} J {36 67} j {36 68} Linefeed {36 69} Linefeed {36 70} Linefeed {36 71} Linefeed {36 72} Meta_j {36 73} Meta_J {36 74} Meta_j {36 75} Meta_J {36 76} Meta_Linefeed {36 77} Meta_Linefeed {36 78} Meta_Linefeed {36 79} Meta_Linefeed {36 80} J {36 81} j {36 82} J {36 83} j {36 84} Linefeed {36 85} Linefeed {36 86} Linefeed {36 87} Linefeed {36 88} Meta_j {36 89} Meta_J {36 90} Meta_j {36 91} Meta_J {36 92} Meta_Linefeed {36 93} Meta_Linefeed {36 94} Meta_Linefeed {36 95} Meta_Linefeed {36 96} J {36 97} j {36 98} J {36 99} j {36 100} Linefeed {36 101} Linefeed {36 102} Linefeed {36 103} Linefeed {36 104} Meta_j {36 105} Meta_J {36 106} Meta_j {36 107} Meta_J {36 108} Meta_Linefeed {36 109} Meta_Linefeed {36 110} Meta_Linefeed {36 111} Meta_Linefeed {36 112} J {36 113} j {36 114} J {36 115} j {36 116} Linefeed {36 117} Linefeed {36 118} Linefeed {36 119} Linefeed {36 120} Meta_j {36 121} Meta_J {36 122} Meta_j {36 123} Meta_J {36 124} Meta_Linefeed {36 125} Meta_Linefeed {36 126} Meta_Linefeed {36 127} Meta_Linefeed {37 0} k {37 1} K {37 2} k {37 3} K {37 4} Control_k {37 5} Control_k {37 6} Control_k {37 7} Control_k {37 8} Meta_k {37 9} Meta_K {37 10} Meta_k {37 11} Meta_K {37 12} Meta_Control_k {37 13} Meta_Control_k {37 14} Meta_Control_k {37 15} Meta_Control_k {37 16} k {37 17} K {37 18} k {37 19} K {37 20} Control_k {37 21} Control_k {37 22} Control_k {37 23} Control_k {37 24} Meta_k {37 25} Meta_K {37 26} Meta_k {37 27} Meta_K {37 28} Meta_Control_k {37 29} Meta_Control_k {37 30} Meta_Control_k {37 31} Meta_Control_k {37 32} k {37 33} K {37 34} k {37 35} K {37 36} Control_k {37 37} Control_k {37 38} Control_k {37 39} Control_k {37 40} Meta_k {37 41} Meta_K {37 42} Meta_k {37 43} Meta_K {37 44} Meta_Control_k {37 45} Meta_Control_k {37 46} Meta_Control_k {37 47} Meta_Control_k {37 48} k {37 49} K {37 50} k {37 51} K {37 52} Control_k {37 53} Control_k {37 54} Control_k {37 55} Control_k {37 56} Meta_k {37 57} Meta_K {37 58} Meta_k {37 59} Meta_K {37 60} Meta_Control_k {37 61} Meta_Control_k {37 62} Meta_Control_k {37 63} Meta_Control_k {37 64} K {37 65} k {37 66} K {37 67} k {37 68} Control_k {37 69} Control_k {37 70} Control_k {37 71} Control_k {37 72} Meta_k {37 73} Meta_K {37 74} Meta_k {37 75} Meta_K {37 76} Meta_Control_k {37 77} Meta_Control_k {37 78} Meta_Control_k {37 79} Meta_Control_k {37 80} K {37 81} k {37 82} K {37 83} k {37 84} Control_k {37 85} Control_k {37 86} Control_k {37 87} Control_k {37 88} Meta_k {37 89} Meta_K {37 90} Meta_k {37 91} Meta_K {37 92} Meta_Control_k {37 93} Meta_Control_k {37 94} Meta_Control_k {37 95} Meta_Control_k {37 96} K {37 97} k {37 98} K {37 99} k {37 100} Control_k {37 101} Control_k {37 102} Control_k {37 103} Control_k {37 104} Meta_k {37 105} Meta_K {37 106} Meta_k {37 107} Meta_K {37 108} Meta_Control_k {37 109} Meta_Control_k {37 110} Meta_Control_k {37 111} Meta_Control_k {37 112} K {37 113} k {37 114} K {37 115} k {37 116} Control_k {37 117} Control_k {37 118} Control_k {37 119} Control_k {37 120} Meta_k {37 121} Meta_K {37 122} Meta_k {37 123} Meta_K {37 124} Meta_Control_k {37 125} Meta_Control_k {37 126} Meta_Control_k {37 127} Meta_Control_k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} Control_l {38 5} Control_l {38 6} Control_l {38 7} Control_l {38 8} Meta_l {38 9} Meta_L {38 10} Meta_l {38 11} Meta_L {38 12} Meta_Control_l {38 13} Meta_Control_l {38 14} Meta_Control_l {38 15} Meta_Control_l {38 16} l {38 17} L {38 18} l {38 19} L {38 20} Control_l {38 21} Control_l {38 22} Control_l {38 23} Control_l {38 24} Meta_l {38 25} Meta_L {38 26} Meta_l {38 27} Meta_L {38 28} Meta_Control_l {38 29} Meta_Control_l {38 30} Meta_Control_l {38 31} Meta_Control_l {38 32} l {38 33} L {38 34} l {38 35} L {38 36} Control_l {38 37} Control_l {38 38} Control_l {38 39} Control_l {38 40} Meta_l {38 41} Meta_L {38 42} Meta_l {38 43} Meta_L {38 44} Meta_Control_l {38 45} Meta_Control_l {38 46} Meta_Control_l {38 47} Meta_Control_l {38 48} l {38 49} L {38 50} l {38 51} L {38 52} Control_l {38 53} Control_l {38 54} Control_l {38 55} Control_l {38 56} Meta_l {38 57} Meta_L {38 58} Meta_l {38 59} Meta_L {38 60} Meta_Control_l {38 61} Meta_Control_l {38 62} Meta_Control_l {38 63} Meta_Control_l {38 64} L {38 65} l {38 66} L {38 67} l {38 68} Control_l {38 69} Control_l {38 70} Control_l {38 71} Control_l {38 72} Meta_l {38 73} Meta_L {38 74} Meta_l {38 75} Meta_L {38 76} Meta_Control_l {38 77} Meta_Control_l {38 78} Meta_Control_l {38 79} Meta_Control_l {38 80} L {38 81} l {38 82} L {38 83} l {38 84} Control_l {38 85} Control_l {38 86} Control_l {38 87} Control_l {38 88} Meta_l {38 89} Meta_L {38 90} Meta_l {38 91} Meta_L {38 92} Meta_Control_l {38 93} Meta_Control_l {38 94} Meta_Control_l {38 95} Meta_Control_l {38 96} L {38 97} l {38 98} L {38 99} l {38 100} Control_l {38 101} Control_l {38 102} Control_l {38 103} Control_l {38 104} Meta_l {38 105} Meta_L {38 106} Meta_l {38 107} Meta_L {38 108} Meta_Control_l {38 109} Meta_Control_l {38 110} Meta_Control_l {38 111} Meta_Control_l {38 112} L {38 113} l {38 114} L {38 115} l {38 116} Control_l {38 117} Control_l {38 118} Control_l {38 119} Control_l {38 120} Meta_l {38 121} Meta_L {38 122} Meta_l {38 123} Meta_L {38 124} Meta_Control_l {38 125} Meta_Control_l {38 126} Meta_Control_l {38 127} Meta_Control_l {39 0} semicolon {39 1} colon {39 2} semicolon {39 3} colon {39 4} semicolon {39 5} colon {39 6} semicolon {39 7} colon {39 8} Meta_semicolon {39 9} Meta_colon {39 10} Meta_semicolon {39 11} Meta_colon {39 12} Meta_semicolon {39 13} Meta_colon {39 14} Meta_semicolon {39 15} Meta_colon {39 16} semicolon {39 17} colon {39 18} semicolon {39 19} colon {39 20} semicolon {39 21} colon {39 22} semicolon {39 23} colon {39 24} Meta_semicolon {39 25} Meta_colon {39 26} Meta_semicolon {39 27} Meta_colon {39 28} Meta_semicolon {39 29} Meta_colon {39 30} Meta_semicolon {39 31} Meta_colon {39 32} semicolon {39 33} colon {39 34} semicolon {39 35} colon {39 36} semicolon {39 37} colon {39 38} semicolon {39 39} colon {39 40} Meta_semicolon {39 41} Meta_colon {39 42} Meta_semicolon {39 43} Meta_colon {39 44} Meta_semicolon {39 45} Meta_colon {39 46} Meta_semicolon {39 47} Meta_colon {39 48} semicolon {39 49} colon {39 50} semicolon {39 51} colon {39 52} semicolon {39 53} colon {39 54} semicolon {39 55} colon {39 56} Meta_semicolon {39 57} Meta_colon {39 58} Meta_semicolon {39 59} Meta_colon {39 60} Meta_semicolon {39 61} Meta_colon {39 62} Meta_semicolon {39 63} Meta_colon {39 64} semicolon {39 65} colon {39 66} semicolon {39 67} colon {39 68} semicolon {39 69} colon {39 70} semicolon {39 71} colon {39 72} Meta_semicolon {39 73} Meta_colon {39 74} Meta_semicolon {39 75} Meta_colon {39 76} Meta_semicolon {39 77} Meta_colon {39 78} Meta_semicolon {39 79} Meta_colon {39 80} semicolon {39 81} colon {39 82} semicolon {39 83} colon {39 84} semicolon {39 85} colon {39 86} semicolon {39 87} colon {39 88} Meta_semicolon {39 89} Meta_colon {39 90} Meta_semicolon {39 91} Meta_colon {39 92} Meta_semicolon {39 93} Meta_colon {39 94} Meta_semicolon {39 95} Meta_colon {39 96} semicolon {39 97} colon {39 98} semicolon {39 99} colon {39 100} semicolon {39 101} colon {39 102} semicolon {39 103} colon {39 104} Meta_semicolon {39 105} Meta_colon {39 106} Meta_semicolon {39 107} Meta_colon {39 108} Meta_semicolon {39 109} Meta_colon {39 110} Meta_semicolon {39 111} Meta_colon {39 112} semicolon {39 113} colon {39 114} semicolon {39 115} colon {39 116} semicolon {39 117} colon {39 118} semicolon {39 119} colon {39 120} Meta_semicolon {39 121} Meta_colon {39 122} Meta_semicolon {39 123} Meta_colon {39 124} Meta_semicolon {39 125} Meta_colon {39 126} Meta_semicolon {39 127} Meta_colon {40 0} apostrophe {40 1} quotedbl {40 2} apostrophe {40 3} quotedbl {40 4} apostrophe {40 5} quotedbl {40 6} apostrophe {40 7} quotedbl {40 8} Meta_apostrophe {40 9} Meta_quotedbl {40 10} Meta_apostrophe {40 11} Meta_quotedbl {40 12} Meta_apostrophe {40 13} Meta_quotedbl {40 14} Meta_apostrophe {40 15} Meta_quotedbl {40 16} apostrophe {40 17} quotedbl {40 18} apostrophe {40 19} quotedbl {40 20} apostrophe {40 21} quotedbl {40 22} apostrophe {40 23} quotedbl {40 24} Meta_apostrophe {40 25} Meta_quotedbl {40 26} Meta_apostrophe {40 27} Meta_quotedbl {40 28} Meta_apostrophe {40 29} Meta_quotedbl {40 30} Meta_apostrophe {40 31} Meta_quotedbl {40 32} apostrophe {40 33} quotedbl {40 34} apostrophe {40 35} quotedbl {40 36} apostrophe {40 37} quotedbl {40 38} apostrophe {40 39} quotedbl {40 40} Meta_apostrophe {40 41} Meta_quotedbl {40 42} Meta_apostrophe {40 43} Meta_quotedbl {40 44} Meta_apostrophe {40 45} Meta_quotedbl {40 46} Meta_apostrophe {40 47} Meta_quotedbl {40 48} apostrophe {40 49} quotedbl {40 50} apostrophe {40 51} quotedbl {40 52} apostrophe {40 53} quotedbl {40 54} apostrophe {40 55} quotedbl {40 56} Meta_apostrophe {40 57} Meta_quotedbl {40 58} Meta_apostrophe {40 59} Meta_quotedbl {40 60} Meta_apostrophe {40 61} Meta_quotedbl {40 62} Meta_apostrophe {40 63} Meta_quotedbl {40 64} apostrophe {40 65} quotedbl {40 66} apostrophe {40 67} quotedbl {40 68} apostrophe {40 69} quotedbl {40 70} apostrophe {40 71} quotedbl {40 72} Meta_apostrophe {40 73} Meta_quotedbl {40 74} Meta_apostrophe {40 75} Meta_quotedbl {40 76} Meta_apostrophe {40 77} Meta_quotedbl {40 78} Meta_apostrophe {40 79} Meta_quotedbl {40 80} apostrophe {40 81} quotedbl {40 82} apostrophe {40 83} quotedbl {40 84} apostrophe {40 85} quotedbl {40 86} apostrophe {40 87} quotedbl {40 88} Meta_apostrophe {40 89} Meta_quotedbl {40 90} Meta_apostrophe {40 91} Meta_quotedbl {40 92} Meta_apostrophe {40 93} Meta_quotedbl {40 94} Meta_apostrophe {40 95} Meta_quotedbl {40 96} apostrophe {40 97} quotedbl {40 98} apostrophe {40 99} quotedbl {40 100} apostrophe {40 101} quotedbl {40 102} apostrophe {40 103} quotedbl {40 104} Meta_apostrophe {40 105} Meta_quotedbl {40 106} Meta_apostrophe {40 107} Meta_quotedbl {40 108} Meta_apostrophe {40 109} Meta_quotedbl {40 110} Meta_apostrophe {40 111} Meta_quotedbl {40 112} apostrophe {40 113} quotedbl {40 114} apostrophe {40 115} quotedbl {40 116} apostrophe {40 117} quotedbl {40 118} apostrophe {40 119} quotedbl {40 120} Meta_apostrophe {40 121} Meta_quotedbl {40 122} Meta_apostrophe {40 123} Meta_quotedbl {40 124} Meta_apostrophe {40 125} Meta_quotedbl {40 126} Meta_apostrophe {40 127} Meta_quotedbl {41 0} grave {41 1} asciitilde {41 2} grave {41 3} asciitilde {41 4} nul {41 5} Control_asciicircum {41 6} nul {41 7} Control_asciicircum {41 8} Meta_grave {41 9} Meta_asciitilde {41 10} Meta_grave {41 11} Meta_asciitilde {41 12} Meta_nul {41 13} Meta_Control_asciicircum {41 14} Meta_nul {41 15} Meta_Control_asciicircum {41 16} grave {41 17} asciitilde {41 18} grave {41 19} asciitilde {41 20} nul {41 21} Control_asciicircum {41 22} nul {41 23} Control_asciicircum {41 24} Meta_grave {41 25} Meta_asciitilde {41 26} Meta_grave {41 27} Meta_asciitilde {41 28} Meta_nul {41 29} Meta_Control_asciicircum {41 30} Meta_nul {41 31} Meta_Control_asciicircum {41 32} grave {41 33} asciitilde {41 34} grave {41 35} asciitilde {41 36} nul {41 37} Control_asciicircum {41 38} nul {41 39} Control_asciicircum {41 40} Meta_grave {41 41} Meta_asciitilde {41 42} Meta_grave {41 43} Meta_asciitilde {41 44} Meta_nul {41 45} Meta_Control_asciicircum {41 46} Meta_nul {41 47} Meta_Control_asciicircum {41 48} grave {41 49} asciitilde {41 50} grave {41 51} asciitilde {41 52} nul {41 53} Control_asciicircum {41 54} nul {41 55} Control_asciicircum {41 56} Meta_grave {41 57} Meta_asciitilde {41 58} Meta_grave {41 59} Meta_asciitilde {41 60} Meta_nul {41 61} Meta_Control_asciicircum {41 62} Meta_nul {41 63} Meta_Control_asciicircum {41 64} grave {41 65} asciitilde {41 66} grave {41 67} asciitilde {41 68} nul {41 69} Control_asciicircum {41 70} nul {41 71} Control_asciicircum {41 72} Meta_grave {41 73} Meta_asciitilde {41 74} Meta_grave {41 75} Meta_asciitilde {41 76} Meta_nul {41 77} Meta_Control_asciicircum {41 78} Meta_nul {41 79} Meta_Control_asciicircum {41 80} grave {41 81} asciitilde {41 82} grave {41 83} asciitilde {41 84} nul {41 85} Control_asciicircum {41 86} nul {41 87} Control_asciicircum {41 88} Meta_grave {41 89} Meta_asciitilde {41 90} Meta_grave {41 91} Meta_asciitilde {41 92} Meta_nul {41 93} Meta_Control_asciicircum {41 94} Meta_nul {41 95} Meta_Control_asciicircum {41 96} grave {41 97} asciitilde {41 98} grave {41 99} asciitilde {41 100} nul {41 101} Control_asciicircum {41 102} nul {41 103} Control_asciicircum {41 104} Meta_grave {41 105} Meta_asciitilde {41 106} Meta_grave {41 107} Meta_asciitilde {41 108} Meta_nul {41 109} Meta_Control_asciicircum {41 110} Meta_nul {41 111} Meta_Control_asciicircum {41 112} grave {41 113} asciitilde {41 114} grave {41 115} asciitilde {41 116} nul {41 117} Control_asciicircum {41 118} nul {41 119} Control_asciicircum {41 120} Meta_grave {41 121} Meta_asciitilde {41 122} Meta_grave {41 123} Meta_asciitilde {41 124} Meta_nul {41 125} Meta_Control_asciicircum {41 126} Meta_nul {41 127} Meta_Control_asciicircum {42 0} Shift {42 1} Shift {42 2} Shift {42 3} Shift {42 4} Shift {42 5} Shift {42 6} Shift {42 7} Shift {42 8} Shift {42 9} Shift {42 10} Shift {42 11} Shift {42 12} Shift {42 13} Shift {42 14} Shift {42 15} Shift {42 16} Shift {42 17} Shift {42 18} Shift {42 19} Shift {42 20} Shift {42 21} Shift {42 22} Shift {42 23} Shift {42 24} Shift {42 25} Shift {42 26} Shift {42 27} Shift {42 28} Shift {42 29} Shift {42 30} Shift {42 31} Shift {42 32} Shift {42 33} Shift {42 34} Shift {42 35} Shift {42 36} Shift {42 37} Shift {42 38} Shift {42 39} Shift {42 40} Shift {42 41} Shift {42 42} Shift {42 43} Shift {42 44} Shift {42 45} Shift {42 46} Shift {42 47} Shift {42 48} Shift {42 49} Shift {42 50} Shift {42 51} Shift {42 52} Shift {42 53} Shift {42 54} Shift {42 55} Shift {42 56} Shift {42 57} Shift {42 58} Shift {42 59} Shift {42 60} Shift {42 61} Shift {42 62} Shift {42 63} Shift {42 64} Shift {42 65} Shift {42 66} Shift {42 67} Shift {42 68} Shift {42 69} Shift {42 70} Shift {42 71} Shift {42 72} Shift {42 73} Shift {42 74} Shift {42 75} Shift {42 76} Shift {42 77} Shift {42 78} Shift {42 79} Shift {42 80} Shift {42 81} Shift {42 82} Shift {42 83} Shift {42 84} Shift {42 85} Shift {42 86} Shift {42 87} Shift {42 88} Shift {42 89} Shift {42 90} Shift {42 91} Shift {42 92} Shift {42 93} Shift {42 94} Shift {42 95} Shift {42 96} Shift {42 97} Shift {42 98} Shift {42 99} Shift {42 100} Shift {42 101} Shift {42 102} Shift {42 103} Shift {42 104} Shift {42 105} Shift {42 106} Shift {42 107} Shift {42 108} Shift {42 109} Shift {42 110} Shift {42 111} Shift {42 112} Shift {42 113} Shift {42 114} Shift {42 115} Shift {42 116} Shift {42 117} Shift {42 118} Shift {42 119} Shift {42 120} Shift {42 121} Shift {42 122} Shift {42 123} Shift {42 124} Shift {42 125} Shift {42 126} Shift {42 127} Shift {43 0} backslash {43 1} bar {43 2} backslash {43 3} bar {43 4} Control_backslash {43 5} Control_backslash {43 6} Control_backslash {43 7} Control_backslash {43 8} Meta_backslash {43 9} Meta_bar {43 10} Meta_backslash {43 11} Meta_bar {43 12} Meta_Control_backslash {43 13} Meta_Control_backslash {43 14} Meta_Control_backslash {43 15} Meta_Control_backslash {43 16} backslash {43 17} bar {43 18} backslash {43 19} bar {43 20} Control_backslash {43 21} Control_backslash {43 22} Control_backslash {43 23} Control_backslash {43 24} Meta_backslash {43 25} Meta_bar {43 26} Meta_backslash {43 27} Meta_bar {43 28} Meta_Control_backslash {43 29} Meta_Control_backslash {43 30} Meta_Control_backslash {43 31} Meta_Control_backslash {43 32} backslash {43 33} bar {43 34} backslash {43 35} bar {43 36} Control_backslash {43 37} Control_backslash {43 38} Control_backslash {43 39} Control_backslash {43 40} Meta_backslash {43 41} Meta_bar {43 42} Meta_backslash {43 43} Meta_bar {43 44} Meta_Control_backslash {43 45} Meta_Control_backslash {43 46} Meta_Control_backslash {43 47} Meta_Control_backslash {43 48} backslash {43 49} bar {43 50} backslash {43 51} bar {43 52} Control_backslash {43 53} Control_backslash {43 54} Control_backslash {43 55} Control_backslash {43 56} Meta_backslash {43 57} Meta_bar {43 58} Meta_backslash {43 59} Meta_bar {43 60} Meta_Control_backslash {43 61} Meta_Control_backslash {43 62} Meta_Control_backslash {43 63} Meta_Control_backslash {43 64} backslash {43 65} bar {43 66} backslash {43 67} bar {43 68} Control_backslash {43 69} Control_backslash {43 70} Control_backslash {43 71} Control_backslash {43 72} Meta_backslash {43 73} Meta_bar {43 74} Meta_backslash {43 75} Meta_bar {43 76} Meta_Control_backslash {43 77} Meta_Control_backslash {43 78} Meta_Control_backslash {43 79} Meta_Control_backslash {43 80} backslash {43 81} bar {43 82} backslash {43 83} bar {43 84} Control_backslash {43 85} Control_backslash {43 86} Control_backslash {43 87} Control_backslash {43 88} Meta_backslash {43 89} Meta_bar {43 90} Meta_backslash {43 91} Meta_bar {43 92} Meta_Control_backslash {43 93} Meta_Control_backslash {43 94} Meta_Control_backslash {43 95} Meta_Control_backslash {43 96} backslash {43 97} bar {43 98} backslash {43 99} bar {43 100} Control_backslash {43 101} Control_backslash {43 102} Control_backslash {43 103} Control_backslash {43 104} Meta_backslash {43 105} Meta_bar {43 106} Meta_backslash {43 107} Meta_bar {43 108} Meta_Control_backslash {43 109} Meta_Control_backslash {43 110} Meta_Control_backslash {43 111} Meta_Control_backslash {43 112} backslash {43 113} bar {43 114} backslash {43 115} bar {43 116} Control_backslash {43 117} Control_backslash {43 118} Control_backslash {43 119} Control_backslash {43 120} Meta_backslash {43 121} Meta_bar {43 122} Meta_backslash {43 123} Meta_bar {43 124} Meta_Control_backslash {43 125} Meta_Control_backslash {43 126} Meta_Control_backslash {43 127} Meta_Control_backslash {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} Control_z {44 5} Control_z {44 6} Control_z {44 7} Control_z {44 8} Meta_z {44 9} Meta_Z {44 10} Meta_z {44 11} Meta_Z {44 12} Meta_Control_z {44 13} Meta_Control_z {44 14} Meta_Control_z {44 15} Meta_Control_z {44 16} z {44 17} Z {44 18} z {44 19} Z {44 20} Control_z {44 21} Control_z {44 22} Control_z {44 23} Control_z {44 24} Meta_z {44 25} Meta_Z {44 26} Meta_z {44 27} Meta_Z {44 28} Meta_Control_z {44 29} Meta_Control_z {44 30} Meta_Control_z {44 31} Meta_Control_z {44 32} z {44 33} Z {44 34} z {44 35} Z {44 36} Control_z {44 37} Control_z {44 38} Control_z {44 39} Control_z {44 40} Meta_z {44 41} Meta_Z {44 42} Meta_z {44 43} Meta_Z {44 44} Meta_Control_z {44 45} Meta_Control_z {44 46} Meta_Control_z {44 47} Meta_Control_z {44 48} z {44 49} Z {44 50} z {44 51} Z {44 52} Control_z {44 53} Control_z {44 54} Control_z {44 55} Control_z {44 56} Meta_z {44 57} Meta_Z {44 58} Meta_z {44 59} Meta_Z {44 60} Meta_Control_z {44 61} Meta_Control_z {44 62} Meta_Control_z {44 63} Meta_Control_z {44 64} Z {44 65} z {44 66} Z {44 67} z {44 68} Control_z {44 69} Control_z {44 70} Control_z {44 71} Control_z {44 72} Meta_z {44 73} Meta_Z {44 74} Meta_z {44 75} Meta_Z {44 76} Meta_Control_z {44 77} Meta_Control_z {44 78} Meta_Control_z {44 79} Meta_Control_z {44 80} Z {44 81} z {44 82} Z {44 83} z {44 84} Control_z {44 85} Control_z {44 86} Control_z {44 87} Control_z {44 88} Meta_z {44 89} Meta_Z {44 90} Meta_z {44 91} Meta_Z {44 92} Meta_Control_z {44 93} Meta_Control_z {44 94} Meta_Control_z {44 95} Meta_Control_z {44 96} Z {44 97} z {44 98} Z {44 99} z {44 100} Control_z {44 101} Control_z {44 102} Control_z {44 103} Control_z {44 104} Meta_z {44 105} Meta_Z {44 106} Meta_z {44 107} Meta_Z {44 108} Meta_Control_z {44 109} Meta_Control_z {44 110} Meta_Control_z {44 111} Meta_Control_z {44 112} Z {44 113} z {44 114} Z {44 115} z {44 116} Control_z {44 117} Control_z {44 118} Control_z {44 119} Control_z {44 120} Meta_z {44 121} Meta_Z {44 122} Meta_z {44 123} Meta_Z {44 124} Meta_Control_z {44 125} Meta_Control_z {44 126} Meta_Control_z {44 127} Meta_Control_z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} Control_x {45 5} Control_x {45 6} Control_x {45 7} Control_x {45 8} Meta_x {45 9} Meta_X {45 10} Meta_x {45 11} Meta_X {45 12} Meta_Control_x {45 13} Meta_Control_x {45 14} Meta_Control_x {45 15} Meta_Control_x {45 16} x {45 17} X {45 18} x {45 19} X {45 20} Control_x {45 21} Control_x {45 22} Control_x {45 23} Control_x {45 24} Meta_x {45 25} Meta_X {45 26} Meta_x {45 27} Meta_X {45 28} Meta_Control_x {45 29} Meta_Control_x {45 30} Meta_Control_x {45 31} Meta_Control_x {45 32} x {45 33} X {45 34} x {45 35} X {45 36} Control_x {45 37} Control_x {45 38} Control_x {45 39} Control_x {45 40} Meta_x {45 41} Meta_X {45 42} Meta_x {45 43} Meta_X {45 44} Meta_Control_x {45 45} Meta_Control_x {45 46} Meta_Control_x {45 47} Meta_Control_x {45 48} x {45 49} X {45 50} x {45 51} X {45 52} Control_x {45 53} Control_x {45 54} Control_x {45 55} Control_x {45 56} Meta_x {45 57} Meta_X {45 58} Meta_x {45 59} Meta_X {45 60} Meta_Control_x {45 61} Meta_Control_x {45 62} Meta_Control_x {45 63} Meta_Control_x {45 64} X {45 65} x {45 66} X {45 67} x {45 68} Control_x {45 69} Control_x {45 70} Control_x {45 71} Control_x {45 72} Meta_x {45 73} Meta_X {45 74} Meta_x {45 75} Meta_X {45 76} Meta_Control_x {45 77} Meta_Control_x {45 78} Meta_Control_x {45 79} Meta_Control_x {45 80} X {45 81} x {45 82} X {45 83} x {45 84} Control_x {45 85} Control_x {45 86} Control_x {45 87} Control_x {45 88} Meta_x {45 89} Meta_X {45 90} Meta_x {45 91} Meta_X {45 92} Meta_Control_x {45 93} Meta_Control_x {45 94} Meta_Control_x {45 95} Meta_Control_x {45 96} X {45 97} x {45 98} X {45 99} x {45 100} Control_x {45 101} Control_x {45 102} Control_x {45 103} Control_x {45 104} Meta_x {45 105} Meta_X {45 106} Meta_x {45 107} Meta_X {45 108} Meta_Control_x {45 109} Meta_Control_x {45 110} Meta_Control_x {45 111} Meta_Control_x {45 112} X {45 113} x {45 114} X {45 115} x {45 116} Control_x {45 117} Control_x {45 118} Control_x {45 119} Control_x {45 120} Meta_x {45 121} Meta_X {45 122} Meta_x {45 123} Meta_X {45 124} Meta_Control_x {45 125} Meta_Control_x {45 126} Meta_Control_x {45 127} Meta_Control_x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} Control_c {46 5} Control_c {46 6} Control_c {46 7} Control_c {46 8} Meta_c {46 9} Meta_C {46 10} Meta_c {46 11} Meta_C {46 12} Meta_Control_c {46 13} Meta_Control_c {46 14} Meta_Control_c {46 15} Meta_Control_c {46 16} c {46 17} C {46 18} c {46 19} C {46 20} Control_c {46 21} Control_c {46 22} Control_c {46 23} Control_c {46 24} Meta_c {46 25} Meta_C {46 26} Meta_c {46 27} Meta_C {46 28} Meta_Control_c {46 29} Meta_Control_c {46 30} Meta_Control_c {46 31} Meta_Control_c {46 32} c {46 33} C {46 34} c {46 35} C {46 36} Control_c {46 37} Control_c {46 38} Control_c {46 39} Control_c {46 40} Meta_c {46 41} Meta_C {46 42} Meta_c {46 43} Meta_C {46 44} Meta_Control_c {46 45} Meta_Control_c {46 46} Meta_Control_c {46 47} Meta_Control_c {46 48} c {46 49} C {46 50} c {46 51} C {46 52} Control_c {46 53} Control_c {46 54} Control_c {46 55} Control_c {46 56} Meta_c {46 57} Meta_C {46 58} Meta_c {46 59} Meta_C {46 60} Meta_Control_c {46 61} Meta_Control_c {46 62} Meta_Control_c {46 63} Meta_Control_c {46 64} C {46 65} c {46 66} C {46 67} c {46 68} Control_c {46 69} Control_c {46 70} Control_c {46 71} Control_c {46 72} Meta_c {46 73} Meta_C {46 74} Meta_c {46 75} Meta_C {46 76} Meta_Control_c {46 77} Meta_Control_c {46 78} Meta_Control_c {46 79} Meta_Control_c {46 80} C {46 81} c {46 82} C {46 83} c {46 84} Control_c {46 85} Control_c {46 86} Control_c {46 87} Control_c {46 88} Meta_c {46 89} Meta_C {46 90} Meta_c {46 91} Meta_C {46 92} Meta_Control_c {46 93} Meta_Control_c {46 94} Meta_Control_c {46 95} Meta_Control_c {46 96} C {46 97} c {46 98} C {46 99} c {46 100} Control_c {46 101} Control_c {46 102} Control_c {46 103} Control_c {46 104} Meta_c {46 105} Meta_C {46 106} Meta_c {46 107} Meta_C {46 108} Meta_Control_c {46 109} Meta_Control_c {46 110} Meta_Control_c {46 111} Meta_Control_c {46 112} C {46 113} c {46 114} C {46 115} c {46 116} Control_c {46 117} Control_c {46 118} Control_c {46 119} Control_c {46 120} Meta_c {46 121} Meta_C {46 122} Meta_c {46 123} Meta_C {46 124} Meta_Control_c {46 125} Meta_Control_c {46 126} Meta_Control_c {46 127} Meta_Control_c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} Control_v {47 5} Control_v {47 6} Control_v {47 7} Control_v {47 8} Meta_v {47 9} Meta_V {47 10} Meta_v {47 11} Meta_V {47 12} Meta_Control_v {47 13} Meta_Control_v {47 14} Meta_Control_v {47 15} Meta_Control_v {47 16} v {47 17} V {47 18} v {47 19} V {47 20} Control_v {47 21} Control_v {47 22} Control_v {47 23} Control_v {47 24} Meta_v {47 25} Meta_V {47 26} Meta_v {47 27} Meta_V {47 28} Meta_Control_v {47 29} Meta_Control_v {47 30} Meta_Control_v {47 31} Meta_Control_v {47 32} v {47 33} V {47 34} v {47 35} V {47 36} Control_v {47 37} Control_v {47 38} Control_v {47 39} Control_v {47 40} Meta_v {47 41} Meta_V {47 42} Meta_v {47 43} Meta_V {47 44} Meta_Control_v {47 45} Meta_Control_v {47 46} Meta_Control_v {47 47} Meta_Control_v {47 48} v {47 49} V {47 50} v {47 51} V {47 52} Control_v {47 53} Control_v {47 54} Control_v {47 55} Control_v {47 56} Meta_v {47 57} Meta_V {47 58} Meta_v {47 59} Meta_V {47 60} Meta_Control_v {47 61} Meta_Control_v {47 62} Meta_Control_v {47 63} Meta_Control_v {47 64} V {47 65} v {47 66} V {47 67} v {47 68} Control_v {47 69} Control_v {47 70} Control_v {47 71} Control_v {47 72} Meta_v {47 73} Meta_V {47 74} Meta_v {47 75} Meta_V {47 76} Meta_Control_v {47 77} Meta_Control_v {47 78} Meta_Control_v {47 79} Meta_Control_v {47 80} V {47 81} v {47 82} V {47 83} v {47 84} Control_v {47 85} Control_v {47 86} Control_v {47 87} Control_v {47 88} Meta_v {47 89} Meta_V {47 90} Meta_v {47 91} Meta_V {47 92} Meta_Control_v {47 93} Meta_Control_v {47 94} Meta_Control_v {47 95} Meta_Control_v {47 96} V {47 97} v {47 98} V {47 99} v {47 100} Control_v {47 101} Control_v {47 102} Control_v {47 103} Control_v {47 104} Meta_v {47 105} Meta_V {47 106} Meta_v {47 107} Meta_V {47 108} Meta_Control_v {47 109} Meta_Control_v {47 110} Meta_Control_v {47 111} Meta_Control_v {47 112} V {47 113} v {47 114} V {47 115} v {47 116} Control_v {47 117} Control_v {47 118} Control_v {47 119} Control_v {47 120} Meta_v {47 121} Meta_V {47 122} Meta_v {47 123} Meta_V {47 124} Meta_Control_v {47 125} Meta_Control_v {47 126} Meta_Control_v {47 127} Meta_Control_v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} Control_b {48 5} Control_b {48 6} Control_b {48 7} Control_b {48 8} Meta_b {48 9} Meta_B {48 10} Meta_b {48 11} Meta_B {48 12} Meta_Control_b {48 13} Meta_Control_b {48 14} Meta_Control_b {48 15} Meta_Control_b {48 16} b {48 17} B {48 18} b {48 19} B {48 20} Control_b {48 21} Control_b {48 22} Control_b {48 23} Control_b {48 24} Meta_b {48 25} Meta_B {48 26} Meta_b {48 27} Meta_B {48 28} Meta_Control_b {48 29} Meta_Control_b {48 30} Meta_Control_b {48 31} Meta_Control_b {48 32} b {48 33} B {48 34} b {48 35} B {48 36} Control_b {48 37} Control_b {48 38} Control_b {48 39} Control_b {48 40} Meta_b {48 41} Meta_B {48 42} Meta_b {48 43} Meta_B {48 44} Meta_Control_b {48 45} Meta_Control_b {48 46} Meta_Control_b {48 47} Meta_Control_b {48 48} b {48 49} B {48 50} b {48 51} B {48 52} Control_b {48 53} Control_b {48 54} Control_b {48 55} Control_b {48 56} Meta_b {48 57} Meta_B {48 58} Meta_b {48 59} Meta_B {48 60} Meta_Control_b {48 61} Meta_Control_b {48 62} Meta_Control_b {48 63} Meta_Control_b {48 64} B {48 65} b {48 66} B {48 67} b {48 68} Control_b {48 69} Control_b {48 70} Control_b {48 71} Control_b {48 72} Meta_b {48 73} Meta_B {48 74} Meta_b {48 75} Meta_B {48 76} Meta_Control_b {48 77} Meta_Control_b {48 78} Meta_Control_b {48 79} Meta_Control_b {48 80} B {48 81} b {48 82} B {48 83} b {48 84} Control_b {48 85} Control_b {48 86} Control_b {48 87} Control_b {48 88} Meta_b {48 89} Meta_B {48 90} Meta_b {48 91} Meta_B {48 92} Meta_Control_b {48 93} Meta_Control_b {48 94} Meta_Control_b {48 95} Meta_Control_b {48 96} B {48 97} b {48 98} B {48 99} b {48 100} Control_b {48 101} Control_b {48 102} Control_b {48 103} Control_b {48 104} Meta_b {48 105} Meta_B {48 106} Meta_b {48 107} Meta_B {48 108} Meta_Control_b {48 109} Meta_Control_b {48 110} Meta_Control_b {48 111} Meta_Control_b {48 112} B {48 113} b {48 114} B {48 115} b {48 116} Control_b {48 117} Control_b {48 118} Control_b {48 119} Control_b {48 120} Meta_b {48 121} Meta_B {48 122} Meta_b {48 123} Meta_B {48 124} Meta_Control_b {48 125} Meta_Control_b {48 126} Meta_Control_b {48 127} Meta_Control_b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} Control_n {49 5} Control_n {49 6} Control_n {49 7} Control_n {49 8} Meta_n {49 9} Meta_N {49 10} Meta_n {49 11} Meta_N {49 12} Meta_Control_n {49 13} Meta_Control_n {49 14} Meta_Control_n {49 15} Meta_Control_n {49 16} n {49 17} N {49 18} n {49 19} N {49 20} Control_n {49 21} Control_n {49 22} Control_n {49 23} Control_n {49 24} Meta_n {49 25} Meta_N {49 26} Meta_n {49 27} Meta_N {49 28} Meta_Control_n {49 29} Meta_Control_n {49 30} Meta_Control_n {49 31} Meta_Control_n {49 32} n {49 33} N {49 34} n {49 35} N {49 36} Control_n {49 37} Control_n {49 38} Control_n {49 39} Control_n {49 40} Meta_n {49 41} Meta_N {49 42} Meta_n {49 43} Meta_N {49 44} Meta_Control_n {49 45} Meta_Control_n {49 46} Meta_Control_n {49 47} Meta_Control_n {49 48} n {49 49} N {49 50} n {49 51} N {49 52} Control_n {49 53} Control_n {49 54} Control_n {49 55} Control_n {49 56} Meta_n {49 57} Meta_N {49 58} Meta_n {49 59} Meta_N {49 60} Meta_Control_n {49 61} Meta_Control_n {49 62} Meta_Control_n {49 63} Meta_Control_n {49 64} N {49 65} n {49 66} N {49 67} n {49 68} Control_n {49 69} Control_n {49 70} Control_n {49 71} Control_n {49 72} Meta_n {49 73} Meta_N {49 74} Meta_n {49 75} Meta_N {49 76} Meta_Control_n {49 77} Meta_Control_n {49 78} Meta_Control_n {49 79} Meta_Control_n {49 80} N {49 81} n {49 82} N {49 83} n {49 84} Control_n {49 85} Control_n {49 86} Control_n {49 87} Control_n {49 88} Meta_n {49 89} Meta_N {49 90} Meta_n {49 91} Meta_N {49 92} Meta_Control_n {49 93} Meta_Control_n {49 94} Meta_Control_n {49 95} Meta_Control_n {49 96} N {49 97} n {49 98} N {49 99} n {49 100} Control_n {49 101} Control_n {49 102} Control_n {49 103} Control_n {49 104} Meta_n {49 105} Meta_N {49 106} Meta_n {49 107} Meta_N {49 108} Meta_Control_n {49 109} Meta_Control_n {49 110} Meta_Control_n {49 111} Meta_Control_n {49 112} N {49 113} n {49 114} N {49 115} n {49 116} Control_n {49 117} Control_n {49 118} Control_n {49 119} Control_n {49 120} Meta_n {49 121} Meta_N {49 122} Meta_n {49 123} Meta_N {49 124} Meta_Control_n {49 125} Meta_Control_n {49 126} Meta_Control_n {49 127} Meta_Control_n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} Return {50 5} Return {50 6} Return {50 7} Return {50 8} Meta_m {50 9} Meta_M {50 10} Meta_m {50 11} Meta_M {50 12} Meta_Control_m {50 13} Meta_Control_m {50 14} Meta_Control_m {50 15} Meta_Control_m {50 16} m {50 17} M {50 18} m {50 19} M {50 20} Return {50 21} Return {50 22} Return {50 23} Return {50 24} Meta_m {50 25} Meta_M {50 26} Meta_m {50 27} Meta_M {50 28} Meta_Control_m {50 29} Meta_Control_m {50 30} Meta_Control_m {50 31} Meta_Control_m {50 32} m {50 33} M {50 34} m {50 35} M {50 36} Return {50 37} Return {50 38} Return {50 39} Return {50 40} Meta_m {50 41} Meta_M {50 42} Meta_m {50 43} Meta_M {50 44} Meta_Control_m {50 45} Meta_Control_m {50 46} Meta_Control_m {50 47} Meta_Control_m {50 48} m {50 49} M {50 50} m {50 51} M {50 52} Return {50 53} Return {50 54} Return {50 55} Return {50 56} Meta_m {50 57} Meta_M {50 58} Meta_m {50 59} Meta_M {50 60} Meta_Control_m {50 61} Meta_Control_m {50 62} Meta_Control_m {50 63} Meta_Control_m {50 64} M {50 65} m {50 66} M {50 67} m {50 68} Return {50 69} Return {50 70} Return {50 71} Return {50 72} Meta_m {50 73} Meta_M {50 74} Meta_m {50 75} Meta_M {50 76} Meta_Control_m {50 77} Meta_Control_m {50 78} Meta_Control_m {50 79} Meta_Control_m {50 80} M {50 81} m {50 82} M {50 83} m {50 84} Return {50 85} Return {50 86} Return {50 87} Return {50 88} Meta_m {50 89} Meta_M {50 90} Meta_m {50 91} Meta_M {50 92} Meta_Control_m {50 93} Meta_Control_m {50 94} Meta_Control_m {50 95} Meta_Control_m {50 96} M {50 97} m {50 98} M {50 99} m {50 100} Return {50 101} Return {50 102} Return {50 103} Return {50 104} Meta_m {50 105} Meta_M {50 106} Meta_m {50 107} Meta_M {50 108} Meta_Control_m {50 109} Meta_Control_m {50 110} Meta_Control_m {50 111} Meta_Control_m {50 112} M {50 113} m {50 114} M {50 115} m {50 116} Return {50 117} Return {50 118} Return {50 119} Return {50 120} Meta_m {50 121} Meta_M {50 122} Meta_m {50 123} Meta_M {50 124} Meta_Control_m {50 125} Meta_Control_m {50 126} Meta_Control_m {50 127} Meta_Control_m {51 0} comma {51 1} less {51 2} comma {51 3} less {51 4} comma {51 5} less {51 6} comma {51 7} less {51 8} Meta_comma {51 9} Meta_less {51 10} Meta_comma {51 11} Meta_less {51 12} Meta_comma {51 13} Meta_less {51 14} Meta_comma {51 15} Meta_less {51 16} comma {51 17} less {51 18} comma {51 19} less {51 20} comma {51 21} less {51 22} comma {51 23} less {51 24} Meta_comma {51 25} Meta_less {51 26} Meta_comma {51 27} Meta_less {51 28} Meta_comma {51 29} Meta_less {51 30} Meta_comma {51 31} Meta_less {51 32} comma {51 33} less {51 34} comma {51 35} less {51 36} comma {51 37} less {51 38} comma {51 39} less {51 40} Meta_comma {51 41} Meta_less {51 42} Meta_comma {51 43} Meta_less {51 44} Meta_comma {51 45} Meta_less {51 46} Meta_comma {51 47} Meta_less {51 48} comma {51 49} less {51 50} comma {51 51} less {51 52} comma {51 53} less {51 54} comma {51 55} less {51 56} Meta_comma {51 57} Meta_less {51 58} Meta_comma {51 59} Meta_less {51 60} Meta_comma {51 61} Meta_less {51 62} Meta_comma {51 63} Meta_less {51 64} comma {51 65} less {51 66} comma {51 67} less {51 68} comma {51 69} less {51 70} comma {51 71} less {51 72} Meta_comma {51 73} Meta_less {51 74} Meta_comma {51 75} Meta_less {51 76} Meta_comma {51 77} Meta_less {51 78} Meta_comma {51 79} Meta_less {51 80} comma {51 81} less {51 82} comma {51 83} less {51 84} comma {51 85} less {51 86} comma {51 87} less {51 88} Meta_comma {51 89} Meta_less {51 90} Meta_comma {51 91} Meta_less {51 92} Meta_comma {51 93} Meta_less {51 94} Meta_comma {51 95} Meta_less {51 96} comma {51 97} less {51 98} comma {51 99} less {51 100} comma {51 101} less {51 102} comma {51 103} less {51 104} Meta_comma {51 105} Meta_less {51 106} Meta_comma {51 107} Meta_less {51 108} Meta_comma {51 109} Meta_less {51 110} Meta_comma {51 111} Meta_less {51 112} comma {51 113} less {51 114} comma {51 115} less {51 116} comma {51 117} less {51 118} comma {51 119} less {51 120} Meta_comma {51 121} Meta_less {51 122} Meta_comma {51 123} Meta_less {51 124} Meta_comma {51 125} Meta_less {51 126} Meta_comma {51 127} Meta_less {52 0} period {52 1} greater {52 2} period {52 3} greater {52 4} Compose {52 5} Compose {52 6} Compose {52 7} Compose {52 8} Meta_period {52 9} Meta_greater {52 10} Meta_period {52 11} Meta_greater {52 12} Compose {52 13} Compose {52 14} Compose {52 15} Compose {52 16} period {52 17} greater {52 18} period {52 19} greater {52 20} Compose {52 21} Compose {52 22} Compose {52 23} Compose {52 24} Meta_period {52 25} Meta_greater {52 26} Meta_period {52 27} Meta_greater {52 28} Compose {52 29} Compose {52 30} Compose {52 31} Compose {52 32} period {52 33} greater {52 34} period {52 35} greater {52 36} Compose {52 37} Compose {52 38} Compose {52 39} Compose {52 40} Meta_period {52 41} Meta_greater {52 42} Meta_period {52 43} Meta_greater {52 44} Compose {52 45} Compose {52 46} Compose {52 47} Compose {52 48} period {52 49} greater {52 50} period {52 51} greater {52 52} Compose {52 53} Compose {52 54} Compose {52 55} Compose {52 56} Meta_period {52 57} Meta_greater {52 58} Meta_period {52 59} Meta_greater {52 60} Compose {52 61} Compose {52 62} Compose {52 63} Compose {52 64} period {52 65} greater {52 66} period {52 67} greater {52 68} Compose {52 69} Compose {52 70} Compose {52 71} Compose {52 72} Meta_period {52 73} Meta_greater {52 74} Meta_period {52 75} Meta_greater {52 76} Compose {52 77} Compose {52 78} Compose {52 79} Compose {52 80} period {52 81} greater {52 82} period {52 83} greater {52 84} Compose {52 85} Compose {52 86} Compose {52 87} Compose {52 88} Meta_period {52 89} Meta_greater {52 90} Meta_period {52 91} Meta_greater {52 92} Compose {52 93} Compose {52 94} Compose {52 95} Compose {52 96} period {52 97} greater {52 98} period {52 99} greater {52 100} Compose {52 101} Compose {52 102} Compose {52 103} Compose {52 104} Meta_period {52 105} Meta_greater {52 106} Meta_period {52 107} Meta_greater {52 108} Compose {52 109} Compose {52 110} Compose {52 111} Compose {52 112} period {52 113} greater {52 114} period {52 115} greater {52 116} Compose {52 117} Compose {52 118} Compose {52 119} Compose {52 120} Meta_period {52 121} Meta_greater {52 122} Meta_period {52 123} Meta_greater {52 124} Compose {52 125} Compose {52 126} Compose {52 127} Compose {53 0} slash {53 1} question {53 2} slash {53 3} question {53 4} Delete {53 5} Delete {53 6} Delete {53 7} Delete {53 8} Meta_slash {53 9} Meta_question {53 10} Meta_slash {53 11} Meta_question {53 12} Meta_Delete {53 13} Meta_Delete {53 14} Meta_Delete {53 15} Meta_Delete {53 16} slash {53 17} question {53 18} slash {53 19} question {53 20} Delete {53 21} Delete {53 22} Delete {53 23} Delete {53 24} Meta_slash {53 25} Meta_question {53 26} Meta_slash {53 27} Meta_question {53 28} Meta_Delete {53 29} Meta_Delete {53 30} Meta_Delete {53 31} Meta_Delete {53 32} slash {53 33} question {53 34} slash {53 35} question {53 36} Delete {53 37} Delete {53 38} Delete {53 39} Delete {53 40} Meta_slash {53 41} Meta_question {53 42} Meta_slash {53 43} Meta_question {53 44} Meta_Delete {53 45} Meta_Delete {53 46} Meta_Delete {53 47} Meta_Delete {53 48} slash {53 49} question {53 50} slash {53 51} question {53 52} Delete {53 53} Delete {53 54} Delete {53 55} Delete {53 56} Meta_slash {53 57} Meta_question {53 58} Meta_slash {53 59} Meta_question {53 60} Meta_Delete {53 61} Meta_Delete {53 62} Meta_Delete {53 63} Meta_Delete {53 64} slash {53 65} question {53 66} slash {53 67} question {53 68} Delete {53 69} Delete {53 70} Delete {53 71} Delete {53 72} Meta_slash {53 73} Meta_question {53 74} Meta_slash {53 75} Meta_question {53 76} Meta_Delete {53 77} Meta_Delete {53 78} Meta_Delete {53 79} Meta_Delete {53 80} slash {53 81} question {53 82} slash {53 83} question {53 84} Delete {53 85} Delete {53 86} Delete {53 87} Delete {53 88} Meta_slash {53 89} Meta_question {53 90} Meta_slash {53 91} Meta_question {53 92} Meta_Delete {53 93} Meta_Delete {53 94} Meta_Delete {53 95} Meta_Delete {53 96} slash {53 97} question {53 98} slash {53 99} question {53 100} Delete {53 101} Delete {53 102} Delete {53 103} Delete {53 104} Meta_slash {53 105} Meta_question {53 106} Meta_slash {53 107} Meta_question {53 108} Meta_Delete {53 109} Meta_Delete {53 110} Meta_Delete {53 111} Meta_Delete {53 112} slash {53 113} question {53 114} slash {53 115} question {53 116} Delete {53 117} Delete {53 118} Delete {53 119} Delete {53 120} Meta_slash {53 121} Meta_question {53 122} Meta_slash {53 123} Meta_question {53 124} Meta_Delete {53 125} Meta_Delete {53 126} Meta_Delete {53 127} Meta_Delete {54 0} Shift {54 1} Shift {54 2} Shift {54 3} Shift {54 4} Shift {54 5} Shift {54 6} Shift {54 7} Shift {54 8} Shift {54 9} Shift {54 10} Shift {54 11} Shift {54 12} Shift {54 13} Shift {54 14} Shift {54 15} Shift {54 16} Shift {54 17} Shift {54 18} Shift {54 19} Shift {54 20} Shift {54 21} Shift {54 22} Shift {54 23} Shift {54 24} Shift {54 25} Shift {54 26} Shift {54 27} Shift {54 28} Shift {54 29} Shift {54 30} Shift {54 31} Shift {54 32} Shift {54 33} Shift {54 34} Shift {54 35} Shift {54 36} Shift {54 37} Shift {54 38} Shift {54 39} Shift {54 40} Shift {54 41} Shift {54 42} Shift {54 43} Shift {54 44} Shift {54 45} Shift {54 46} Shift {54 47} Shift {54 48} Shift {54 49} Shift {54 50} Shift {54 51} Shift {54 52} Shift {54 53} Shift {54 54} Shift {54 55} Shift {54 56} Shift {54 57} Shift {54 58} Shift {54 59} Shift {54 60} Shift {54 61} Shift {54 62} Shift {54 63} Shift {54 64} Shift {54 65} Shift {54 66} Shift {54 67} Shift {54 68} Shift {54 69} Shift {54 70} Shift {54 71} Shift {54 72} Shift {54 73} Shift {54 74} Shift {54 75} Shift {54 76} Shift {54 77} Shift {54 78} Shift {54 79} Shift {54 80} Shift {54 81} Shift {54 82} Shift {54 83} Shift {54 84} Shift {54 85} Shift {54 86} Shift {54 87} Shift {54 88} Shift {54 89} Shift {54 90} Shift {54 91} Shift {54 92} Shift {54 93} Shift {54 94} Shift {54 95} Shift {54 96} Shift {54 97} Shift {54 98} Shift {54 99} Shift {54 100} Shift {54 101} Shift {54 102} Shift {54 103} Shift {54 104} Shift {54 105} Shift {54 106} Shift {54 107} Shift {54 108} Shift {54 109} Shift {54 110} Shift {54 111} Shift {54 112} Shift {54 113} Shift {54 114} Shift {54 115} Shift {54 116} Shift {54 117} Shift {54 118} Shift {54 119} Shift {54 120} Shift {54 121} Shift {54 122} Shift {54 123} Shift {54 124} Shift {54 125} Shift {54 126} Shift {54 127} Shift {55 0} KP_Multiply {55 1} KP_Multiply {55 2} Hex_C {55 3} KP_Multiply {55 4} KP_Multiply {55 5} KP_Multiply {55 6} KP_Multiply {55 7} KP_Multiply {55 8} KP_Multiply {55 9} Hex_C {55 10} KP_Multiply {55 11} KP_Multiply {55 12} KP_Multiply {55 13} KP_Multiply {55 14} KP_Multiply {55 15} KP_Multiply {55 16} KP_Multiply {55 17} KP_Multiply {55 18} Hex_C {55 19} KP_Multiply {55 20} KP_Multiply {55 21} KP_Multiply {55 22} KP_Multiply {55 23} KP_Multiply {55 24} KP_Multiply {55 25} Hex_C {55 26} KP_Multiply {55 27} KP_Multiply {55 28} KP_Multiply {55 29} KP_Multiply {55 30} KP_Multiply {55 31} KP_Multiply {55 32} KP_Multiply {55 33} KP_Multiply {55 34} Hex_C {55 35} KP_Multiply {55 36} KP_Multiply {55 37} KP_Multiply {55 38} KP_Multiply {55 39} KP_Multiply {55 40} KP_Multiply {55 41} Hex_C {55 42} KP_Multiply {55 43} KP_Multiply {55 44} KP_Multiply {55 45} KP_Multiply {55 46} KP_Multiply {55 47} KP_Multiply {55 48} KP_Multiply {55 49} KP_Multiply {55 50} Hex_C {55 51} KP_Multiply {55 52} KP_Multiply {55 53} KP_Multiply {55 54} KP_Multiply {55 55} KP_Multiply {55 56} KP_Multiply {55 57} Hex_C {55 58} KP_Multiply {55 59} KP_Multiply {55 60} KP_Multiply {55 61} KP_Multiply {55 62} KP_Multiply {55 63} KP_Multiply {55 64} KP_Multiply {55 65} KP_Multiply {55 66} Hex_C {55 67} KP_Multiply {55 68} KP_Multiply {55 69} KP_Multiply {55 70} KP_Multiply {55 71} KP_Multiply {55 72} KP_Multiply {55 73} Hex_C {55 74} KP_Multiply {55 75} KP_Multiply {55 76} KP_Multiply {55 77} KP_Multiply {55 78} KP_Multiply {55 79} KP_Multiply {55 80} KP_Multiply {55 81} KP_Multiply {55 82} Hex_C {55 83} KP_Multiply {55 84} KP_Multiply {55 85} KP_Multiply {55 86} KP_Multiply {55 87} KP_Multiply {55 88} KP_Multiply {55 89} Hex_C {55 90} KP_Multiply {55 91} KP_Multiply {55 92} KP_Multiply {55 93} KP_Multiply {55 94} KP_Multiply {55 95} KP_Multiply {55 96} KP_Multiply {55 97} KP_Multiply {55 98} Hex_C {55 99} KP_Multiply {55 100} KP_Multiply {55 101} KP_Multiply {55 102} KP_Multiply {55 103} KP_Multiply {55 104} KP_Multiply {55 105} Hex_C {55 106} KP_Multiply {55 107} KP_Multiply {55 108} KP_Multiply {55 109} KP_Multiply {55 110} KP_Multiply {55 111} KP_Multiply {55 112} KP_Multiply {55 113} KP_Multiply {55 114} Hex_C {55 115} KP_Multiply {55 116} KP_Multiply {55 117} KP_Multiply {55 118} KP_Multiply {55 119} KP_Multiply {55 120} KP_Multiply {55 121} Hex_C {55 122} KP_Multiply {55 123} KP_Multiply {55 124} KP_Multiply {55 125} KP_Multiply {55 126} KP_Multiply {55 127} KP_Multiply {56 0} Alt {56 1} Alt {56 2} Alt {56 3} Alt {56 4} Alt {56 5} Alt {56 6} Alt {56 7} Alt {56 8} Alt {56 9} Alt {56 10} Alt {56 11} Alt {56 12} Alt {56 13} Alt {56 14} Alt {56 15} Alt {56 16} Alt {56 17} Alt {56 18} Alt {56 19} Alt {56 20} Alt {56 21} Alt {56 22} Alt {56 23} Alt {56 24} Alt {56 25} Alt {56 26} Alt {56 27} Alt {56 28} Alt {56 29} Alt {56 30} Alt {56 31} Alt {56 32} Alt {56 33} Alt {56 34} Alt {56 35} Alt {56 36} Alt {56 37} Alt {56 38} Alt {56 39} Alt {56 40} Alt {56 41} Alt {56 42} Alt {56 43} Alt {56 44} Alt {56 45} Alt {56 46} Alt {56 47} Alt {56 48} Alt {56 49} Alt {56 50} Alt {56 51} Alt {56 52} Alt {56 53} Alt {56 54} Alt {56 55} Alt {56 56} Alt {56 57} Alt {56 58} Alt {56 59} Alt {56 60} Alt {56 61} Alt {56 62} Alt {56 63} Alt {56 64} Alt {56 65} Alt {56 66} Alt {56 67} Alt {56 68} Alt {56 69} Alt {56 70} Alt {56 71} Alt {56 72} Alt {56 73} Alt {56 74} Alt {56 75} Alt {56 76} Alt {56 77} Alt {56 78} Alt {56 79} Alt {56 80} Alt {56 81} Alt {56 82} Alt {56 83} Alt {56 84} Alt {56 85} Alt {56 86} Alt {56 87} Alt {56 88} Alt {56 89} Alt {56 90} Alt {56 91} Alt {56 92} Alt {56 93} Alt {56 94} Alt {56 95} Alt {56 96} Alt {56 97} Alt {56 98} Alt {56 99} Alt {56 100} Alt {56 101} Alt {56 102} Alt {56 103} Alt {56 104} Alt {56 105} Alt {56 106} Alt {56 107} Alt {56 108} Alt {56 109} Alt {56 110} Alt {56 111} Alt {56 112} Alt {56 113} Alt {56 114} Alt {56 115} Alt {56 116} Alt {56 117} Alt {56 118} Alt {56 119} Alt {56 120} Alt {56 121} Alt {56 122} Alt {56 123} Alt {56 124} Alt {56 125} Alt {56 126} Alt {56 127} Alt {57 0} space {57 1} space {57 2} space {57 3} space {57 4} nul {57 5} nul {57 6} nul {57 7} nul {57 8} Meta_space {57 9} Meta_space {57 10} Meta_space {57 11} Meta_space {57 12} Meta_nul {57 13} Meta_nul {57 14} Meta_nul {57 15} Meta_nul {57 16} space {57 17} space {57 18} space {57 19} space {57 20} nul {57 21} nul {57 22} nul {57 23} nul {57 24} Meta_space {57 25} Meta_space {57 26} Meta_space {57 27} Meta_space {57 28} Meta_nul {57 29} Meta_nul {57 30} Meta_nul {57 31} Meta_nul {57 32} space {57 33} space {57 34} space {57 35} space {57 36} nul {57 37} nul {57 38} nul {57 39} nul {57 40} Meta_space {57 41} Meta_space {57 42} Meta_space {57 43} Meta_space {57 44} Meta_nul {57 45} Meta_nul {57 46} Meta_nul {57 47} Meta_nul {57 48} space {57 49} space {57 50} space {57 51} space {57 52} nul {57 53} nul {57 54} nul {57 55} nul {57 56} Meta_space {57 57} Meta_space {57 58} Meta_space {57 59} Meta_space {57 60} Meta_nul {57 61} Meta_nul {57 62} Meta_nul {57 63} Meta_nul {57 64} space {57 65} space {57 66} space {57 67} space {57 68} nul {57 69} nul {57 70} nul {57 71} nul {57 72} Meta_space {57 73} Meta_space {57 74} Meta_space {57 75} Meta_space {57 76} Meta_nul {57 77} Meta_nul {57 78} Meta_nul {57 79} Meta_nul {57 80} space {57 81} space {57 82} space {57 83} space {57 84} nul {57 85} nul {57 86} nul {57 87} nul {57 88} Meta_space {57 89} Meta_space {57 90} Meta_space {57 91} Meta_space {57 92} Meta_nul {57 93} Meta_nul {57 94} Meta_nul {57 95} Meta_nul {57 96} space {57 97} space {57 98} space {57 99} space {57 100} nul {57 101} nul {57 102} nul {57 103} nul {57 104} Meta_space {57 105} Meta_space {57 106} Meta_space {57 107} Meta_space {57 108} Meta_nul {57 109} Meta_nul {57 110} Meta_nul {57 111} Meta_nul {57 112} space {57 113} space {57 114} space {57 115} space {57 116} nul {57 117} nul {57 118} nul {57 119} nul {57 120} Meta_space {57 121} Meta_space {57 122} Meta_space {57 123} Meta_space {57 124} Meta_nul {57 125} Meta_nul {57 126} Meta_nul {57 127} Meta_nul {58 0} Caps_Lock {58 1} Caps_Lock {58 2} Caps_Lock {58 3} Caps_Lock {58 4} Caps_Lock {58 5} Caps_Lock {58 6} Caps_Lock {58 7} Caps_Lock {58 8} Caps_Lock {58 9} Caps_Lock {58 10} Caps_Lock {58 11} Caps_Lock {58 12} Caps_Lock {58 13} Caps_Lock {58 14} Caps_Lock {58 15} Caps_Lock {58 16} Caps_Lock {58 17} Caps_Lock {58 18} Caps_Lock {58 19} Caps_Lock {58 20} Caps_Lock {58 21} Caps_Lock {58 22} Caps_Lock {58 23} Caps_Lock {58 24} Caps_Lock {58 25} Caps_Lock {58 26} Caps_Lock {58 27} Caps_Lock {58 28} Caps_Lock {58 29} Caps_Lock {58 30} Caps_Lock {58 31} Caps_Lock {58 32} Caps_Lock {58 33} Caps_Lock {58 34} Caps_Lock {58 35} Caps_Lock {58 36} Caps_Lock {58 37} Caps_Lock {58 38} Caps_Lock {58 39} Caps_Lock {58 40} Caps_Lock {58 41} Caps_Lock {58 42} Caps_Lock {58 43} Caps_Lock {58 44} Caps_Lock {58 45} Caps_Lock {58 46} Caps_Lock {58 47} Caps_Lock {58 48} Caps_Lock {58 49} Caps_Lock {58 50} Caps_Lock {58 51} Caps_Lock {58 52} Caps_Lock {58 53} Caps_Lock {58 54} Caps_Lock {58 55} Caps_Lock {58 56} Caps_Lock {58 57} Caps_Lock {58 58} Caps_Lock {58 59} Caps_Lock {58 60} Caps_Lock {58 61} Caps_Lock {58 62} Caps_Lock {58 63} Caps_Lock {58 64} Caps_Lock {58 65} Caps_Lock {58 66} Caps_Lock {58 67} Caps_Lock {58 68} Caps_Lock {58 69} Caps_Lock {58 70} Caps_Lock {58 71} Caps_Lock {58 72} Caps_Lock {58 73} Caps_Lock {58 74} Caps_Lock {58 75} Caps_Lock {58 76} Caps_Lock {58 77} Caps_Lock {58 78} Caps_Lock {58 79} Caps_Lock {58 80} Caps_Lock {58 81} Caps_Lock {58 82} Caps_Lock {58 83} Caps_Lock {58 84} Caps_Lock {58 85} Caps_Lock {58 86} Caps_Lock {58 87} Caps_Lock {58 88} Caps_Lock {58 89} Caps_Lock {58 90} Caps_Lock {58 91} Caps_Lock {58 92} Caps_Lock {58 93} Caps_Lock {58 94} Caps_Lock {58 95} Caps_Lock {58 96} Caps_Lock {58 97} Caps_Lock {58 98} Caps_Lock {58 99} Caps_Lock {58 100} Caps_Lock {58 101} Caps_Lock {58 102} Caps_Lock {58 103} Caps_Lock {58 104} Caps_Lock {58 105} Caps_Lock {58 106} Caps_Lock {58 107} Caps_Lock {58 108} Caps_Lock {58 109} Caps_Lock {58 110} Caps_Lock {58 111} Caps_Lock {58 112} Caps_Lock {58 113} Caps_Lock {58 114} Caps_Lock {58 115} Caps_Lock {58 116} Caps_Lock {58 117} Caps_Lock {58 118} Caps_Lock {58 119} Caps_Lock {58 120} Caps_Lock {58 121} Caps_Lock {58 122} Caps_Lock {58 123} Caps_Lock {58 124} Caps_Lock {58 125} Caps_Lock {58 126} Caps_Lock {58 127} Caps_Lock {59 0} F1 {59 1} F13 {59 2} Console_13 {59 3} Console_25 {59 4} F25 {59 5} F37 {59 6} Console_13 {59 7} Console_25 {59 8} Console_1 {59 9} Console_13 {59 10} F1 {59 11} F1 {59 12} Console_1 {59 13} Console_13 {59 14} F1 {59 15} F1 {59 16} F1 {59 17} F13 {59 18} Console_13 {59 19} Console_25 {59 20} F25 {59 21} F37 {59 22} Console_13 {59 23} Console_25 {59 24} Console_1 {59 25} Console_13 {59 26} F1 {59 27} F1 {59 28} Console_1 {59 29} Console_13 {59 30} F1 {59 31} F1 {59 32} F1 {59 33} F13 {59 34} Console_13 {59 35} Console_25 {59 36} F25 {59 37} F37 {59 38} Console_13 {59 39} Console_25 {59 40} Console_1 {59 41} Console_13 {59 42} F1 {59 43} F1 {59 44} Console_1 {59 45} Console_13 {59 46} F1 {59 47} F1 {59 48} F1 {59 49} F13 {59 50} Console_13 {59 51} Console_25 {59 52} F25 {59 53} F37 {59 54} Console_13 {59 55} Console_25 {59 56} Console_1 {59 57} Console_13 {59 58} F1 {59 59} F1 {59 60} Console_1 {59 61} Console_13 {59 62} F1 {59 63} F1 {59 64} F1 {59 65} F13 {59 66} Console_13 {59 67} Console_25 {59 68} F25 {59 69} F37 {59 70} Console_13 {59 71} Console_25 {59 72} Console_1 {59 73} Console_13 {59 74} F1 {59 75} F1 {59 76} Console_1 {59 77} Console_13 {59 78} F1 {59 79} F1 {59 80} F1 {59 81} F13 {59 82} Console_13 {59 83} Console_25 {59 84} F25 {59 85} F37 {59 86} Console_13 {59 87} Console_25 {59 88} Console_1 {59 89} Console_13 {59 90} F1 {59 91} F1 {59 92} Console_1 {59 93} Console_13 {59 94} F1 {59 95} F1 {59 96} F1 {59 97} F13 {59 98} Console_13 {59 99} Console_25 {59 100} F25 {59 101} F37 {59 102} Console_13 {59 103} Console_25 {59 104} Console_1 {59 105} Console_13 {59 106} F1 {59 107} F1 {59 108} Console_1 {59 109} Console_13 {59 110} F1 {59 111} F1 {59 112} F1 {59 113} F13 {59 114} Console_13 {59 115} Console_25 {59 116} F25 {59 117} F37 {59 118} Console_13 {59 119} Console_25 {59 120} Console_1 {59 121} Console_13 {59 122} F1 {59 123} F1 {59 124} Console_1 {59 125} Console_13 {59 126} F1 {59 127} F1 {60 0} F2 {60 1} F14 {60 2} Console_14 {60 3} Console_26 {60 4} F26 {60 5} F38 {60 6} Console_14 {60 7} Console_26 {60 8} Console_2 {60 9} Console_14 {60 10} F2 {60 11} F2 {60 12} Console_2 {60 13} Console_14 {60 14} F2 {60 15} F2 {60 16} F2 {60 17} F14 {60 18} Console_14 {60 19} Console_26 {60 20} F26 {60 21} F38 {60 22} Console_14 {60 23} Console_26 {60 24} Console_2 {60 25} Console_14 {60 26} F2 {60 27} F2 {60 28} Console_2 {60 29} Console_14 {60 30} F2 {60 31} F2 {60 32} F2 {60 33} F14 {60 34} Console_14 {60 35} Console_26 {60 36} F26 {60 37} F38 {60 38} Console_14 {60 39} Console_26 {60 40} Console_2 {60 41} Console_14 {60 42} F2 {60 43} F2 {60 44} Console_2 {60 45} Console_14 {60 46} F2 {60 47} F2 {60 48} F2 {60 49} F14 {60 50} Console_14 {60 51} Console_26 {60 52} F26 {60 53} F38 {60 54} Console_14 {60 55} Console_26 {60 56} Console_2 {60 57} Console_14 {60 58} F2 {60 59} F2 {60 60} Console_2 {60 61} Console_14 {60 62} F2 {60 63} F2 {60 64} F2 {60 65} F14 {60 66} Console_14 {60 67} Console_26 {60 68} F26 {60 69} F38 {60 70} Console_14 {60 71} Console_26 {60 72} Console_2 {60 73} Console_14 {60 74} F2 {60 75} F2 {60 76} Console_2 {60 77} Console_14 {60 78} F2 {60 79} F2 {60 80} F2 {60 81} F14 {60 82} Console_14 {60 83} Console_26 {60 84} F26 {60 85} F38 {60 86} Console_14 {60 87} Console_26 {60 88} Console_2 {60 89} Console_14 {60 90} F2 {60 91} F2 {60 92} Console_2 {60 93} Console_14 {60 94} F2 {60 95} F2 {60 96} F2 {60 97} F14 {60 98} Console_14 {60 99} Console_26 {60 100} F26 {60 101} F38 {60 102} Console_14 {60 103} Console_26 {60 104} Console_2 {60 105} Console_14 {60 106} F2 {60 107} F2 {60 108} Console_2 {60 109} Console_14 {60 110} F2 {60 111} F2 {60 112} F2 {60 113} F14 {60 114} Console_14 {60 115} Console_26 {60 116} F26 {60 117} F38 {60 118} Console_14 {60 119} Console_26 {60 120} Console_2 {60 121} Console_14 {60 122} F2 {60 123} F2 {60 124} Console_2 {60 125} Console_14 {60 126} F2 {60 127} F2 {61 0} F3 {61 1} F15 {61 2} Console_15 {61 3} Console_27 {61 4} F27 {61 5} F39 {61 6} Console_15 {61 7} Console_27 {61 8} Console_3 {61 9} Console_15 {61 10} F3 {61 11} F3 {61 12} Console_3 {61 13} Console_15 {61 14} F3 {61 15} F3 {61 16} F3 {61 17} F15 {61 18} Console_15 {61 19} Console_27 {61 20} F27 {61 21} F39 {61 22} Console_15 {61 23} Console_27 {61 24} Console_3 {61 25} Console_15 {61 26} F3 {61 27} F3 {61 28} Console_3 {61 29} Console_15 {61 30} F3 {61 31} F3 {61 32} F3 {61 33} F15 {61 34} Console_15 {61 35} Console_27 {61 36} F27 {61 37} F39 {61 38} Console_15 {61 39} Console_27 {61 40} Console_3 {61 41} Console_15 {61 42} F3 {61 43} F3 {61 44} Console_3 {61 45} Console_15 {61 46} F3 {61 47} F3 {61 48} F3 {61 49} F15 {61 50} Console_15 {61 51} Console_27 {61 52} F27 {61 53} F39 {61 54} Console_15 {61 55} Console_27 {61 56} Console_3 {61 57} Console_15 {61 58} F3 {61 59} F3 {61 60} Console_3 {61 61} Console_15 {61 62} F3 {61 63} F3 {61 64} F3 {61 65} F15 {61 66} Console_15 {61 67} Console_27 {61 68} F27 {61 69} F39 {61 70} Console_15 {61 71} Console_27 {61 72} Console_3 {61 73} Console_15 {61 74} F3 {61 75} F3 {61 76} Console_3 {61 77} Console_15 {61 78} F3 {61 79} F3 {61 80} F3 {61 81} F15 {61 82} Console_15 {61 83} Console_27 {61 84} F27 {61 85} F39 {61 86} Console_15 {61 87} Console_27 {61 88} Console_3 {61 89} Console_15 {61 90} F3 {61 91} F3 {61 92} Console_3 {61 93} Console_15 {61 94} F3 {61 95} F3 {61 96} F3 {61 97} F15 {61 98} Console_15 {61 99} Console_27 {61 100} F27 {61 101} F39 {61 102} Console_15 {61 103} Console_27 {61 104} Console_3 {61 105} Console_15 {61 106} F3 {61 107} F3 {61 108} Console_3 {61 109} Console_15 {61 110} F3 {61 111} F3 {61 112} F3 {61 113} F15 {61 114} Console_15 {61 115} Console_27 {61 116} F27 {61 117} F39 {61 118} Console_15 {61 119} Console_27 {61 120} Console_3 {61 121} Console_15 {61 122} F3 {61 123} F3 {61 124} Console_3 {61 125} Console_15 {61 126} F3 {61 127} F3 {62 0} F4 {62 1} F16 {62 2} Console_16 {62 3} Console_28 {62 4} F28 {62 5} F40 {62 6} Console_16 {62 7} Console_28 {62 8} Console_4 {62 9} Console_16 {62 10} F4 {62 11} F4 {62 12} Console_4 {62 13} Console_16 {62 14} F4 {62 15} F4 {62 16} F4 {62 17} F16 {62 18} Console_16 {62 19} Console_28 {62 20} F28 {62 21} F40 {62 22} Console_16 {62 23} Console_28 {62 24} Console_4 {62 25} Console_16 {62 26} F4 {62 27} F4 {62 28} Console_4 {62 29} Console_16 {62 30} F4 {62 31} F4 {62 32} F4 {62 33} F16 {62 34} Console_16 {62 35} Console_28 {62 36} F28 {62 37} F40 {62 38} Console_16 {62 39} Console_28 {62 40} Console_4 {62 41} Console_16 {62 42} F4 {62 43} F4 {62 44} Console_4 {62 45} Console_16 {62 46} F4 {62 47} F4 {62 48} F4 {62 49} F16 {62 50} Console_16 {62 51} Console_28 {62 52} F28 {62 53} F40 {62 54} Console_16 {62 55} Console_28 {62 56} Console_4 {62 57} Console_16 {62 58} F4 {62 59} F4 {62 60} Console_4 {62 61} Console_16 {62 62} F4 {62 63} F4 {62 64} F4 {62 65} F16 {62 66} Console_16 {62 67} Console_28 {62 68} F28 {62 69} F40 {62 70} Console_16 {62 71} Console_28 {62 72} Console_4 {62 73} Console_16 {62 74} F4 {62 75} F4 {62 76} Console_4 {62 77} Console_16 {62 78} F4 {62 79} F4 {62 80} F4 {62 81} F16 {62 82} Console_16 {62 83} Console_28 {62 84} F28 {62 85} F40 {62 86} Console_16 {62 87} Console_28 {62 88} Console_4 {62 89} Console_16 {62 90} F4 {62 91} F4 {62 92} Console_4 {62 93} Console_16 {62 94} F4 {62 95} F4 {62 96} F4 {62 97} F16 {62 98} Console_16 {62 99} Console_28 {62 100} F28 {62 101} F40 {62 102} Console_16 {62 103} Console_28 {62 104} Console_4 {62 105} Console_16 {62 106} F4 {62 107} F4 {62 108} Console_4 {62 109} Console_16 {62 110} F4 {62 111} F4 {62 112} F4 {62 113} F16 {62 114} Console_16 {62 115} Console_28 {62 116} F28 {62 117} F40 {62 118} Console_16 {62 119} Console_28 {62 120} Console_4 {62 121} Console_16 {62 122} F4 {62 123} F4 {62 124} Console_4 {62 125} Console_16 {62 126} F4 {62 127} F4 {63 0} F5 {63 1} F17 {63 2} Console_17 {63 3} Console_29 {63 4} F29 {63 5} F41 {63 6} Console_17 {63 7} Console_29 {63 8} Console_5 {63 9} Console_17 {63 10} F5 {63 11} F5 {63 12} Console_5 {63 13} Console_17 {63 14} F5 {63 15} F5 {63 16} F5 {63 17} F17 {63 18} Console_17 {63 19} Console_29 {63 20} F29 {63 21} F41 {63 22} Console_17 {63 23} Console_29 {63 24} Console_5 {63 25} Console_17 {63 26} F5 {63 27} F5 {63 28} Console_5 {63 29} Console_17 {63 30} F5 {63 31} F5 {63 32} F5 {63 33} F17 {63 34} Console_17 {63 35} Console_29 {63 36} F29 {63 37} F41 {63 38} Console_17 {63 39} Console_29 {63 40} Console_5 {63 41} Console_17 {63 42} F5 {63 43} F5 {63 44} Console_5 {63 45} Console_17 {63 46} F5 {63 47} F5 {63 48} F5 {63 49} F17 {63 50} Console_17 {63 51} Console_29 {63 52} F29 {63 53} F41 {63 54} Console_17 {63 55} Console_29 {63 56} Console_5 {63 57} Console_17 {63 58} F5 {63 59} F5 {63 60} Console_5 {63 61} Console_17 {63 62} F5 {63 63} F5 {63 64} F5 {63 65} F17 {63 66} Console_17 {63 67} Console_29 {63 68} F29 {63 69} F41 {63 70} Console_17 {63 71} Console_29 {63 72} Console_5 {63 73} Console_17 {63 74} F5 {63 75} F5 {63 76} Console_5 {63 77} Console_17 {63 78} F5 {63 79} F5 {63 80} F5 {63 81} F17 {63 82} Console_17 {63 83} Console_29 {63 84} F29 {63 85} F41 {63 86} Console_17 {63 87} Console_29 {63 88} Console_5 {63 89} Console_17 {63 90} F5 {63 91} F5 {63 92} Console_5 {63 93} Console_17 {63 94} F5 {63 95} F5 {63 96} F5 {63 97} F17 {63 98} Console_17 {63 99} Console_29 {63 100} F29 {63 101} F41 {63 102} Console_17 {63 103} Console_29 {63 104} Console_5 {63 105} Console_17 {63 106} F5 {63 107} F5 {63 108} Console_5 {63 109} Console_17 {63 110} F5 {63 111} F5 {63 112} F5 {63 113} F17 {63 114} Console_17 {63 115} Console_29 {63 116} F29 {63 117} F41 {63 118} Console_17 {63 119} Console_29 {63 120} Console_5 {63 121} Console_17 {63 122} F5 {63 123} F5 {63 124} Console_5 {63 125} Console_17 {63 126} F5 {63 127} F5 {64 0} F6 {64 1} F18 {64 2} Console_18 {64 3} Console_30 {64 4} F30 {64 5} F42 {64 6} Console_18 {64 7} Console_30 {64 8} Console_6 {64 9} Console_18 {64 10} F6 {64 11} F6 {64 12} Console_6 {64 13} Console_18 {64 14} F6 {64 15} F6 {64 16} F6 {64 17} F18 {64 18} Console_18 {64 19} Console_30 {64 20} F30 {64 21} F42 {64 22} Console_18 {64 23} Console_30 {64 24} Console_6 {64 25} Console_18 {64 26} F6 {64 27} F6 {64 28} Console_6 {64 29} Console_18 {64 30} F6 {64 31} F6 {64 32} F6 {64 33} F18 {64 34} Console_18 {64 35} Console_30 {64 36} F30 {64 37} F42 {64 38} Console_18 {64 39} Console_30 {64 40} Console_6 {64 41} Console_18 {64 42} F6 {64 43} F6 {64 44} Console_6 {64 45} Console_18 {64 46} F6 {64 47} F6 {64 48} F6 {64 49} F18 {64 50} Console_18 {64 51} Console_30 {64 52} F30 {64 53} F42 {64 54} Console_18 {64 55} Console_30 {64 56} Console_6 {64 57} Console_18 {64 58} F6 {64 59} F6 {64 60} Console_6 {64 61} Console_18 {64 62} F6 {64 63} F6 {64 64} F6 {64 65} F18 {64 66} Console_18 {64 67} Console_30 {64 68} F30 {64 69} F42 {64 70} Console_18 {64 71} Console_30 {64 72} Console_6 {64 73} Console_18 {64 74} F6 {64 75} F6 {64 76} Console_6 {64 77} Console_18 {64 78} F6 {64 79} F6 {64 80} F6 {64 81} F18 {64 82} Console_18 {64 83} Console_30 {64 84} F30 {64 85} F42 {64 86} Console_18 {64 87} Console_30 {64 88} Console_6 {64 89} Console_18 {64 90} F6 {64 91} F6 {64 92} Console_6 {64 93} Console_18 {64 94} F6 {64 95} F6 {64 96} F6 {64 97} F18 {64 98} Console_18 {64 99} Console_30 {64 100} F30 {64 101} F42 {64 102} Console_18 {64 103} Console_30 {64 104} Console_6 {64 105} Console_18 {64 106} F6 {64 107} F6 {64 108} Console_6 {64 109} Console_18 {64 110} F6 {64 111} F6 {64 112} F6 {64 113} F18 {64 114} Console_18 {64 115} Console_30 {64 116} F30 {64 117} F42 {64 118} Console_18 {64 119} Console_30 {64 120} Console_6 {64 121} Console_18 {64 122} F6 {64 123} F6 {64 124} Console_6 {64 125} Console_18 {64 126} F6 {64 127} F6 {65 0} F7 {65 1} F19 {65 2} Console_19 {65 3} Console_31 {65 4} F31 {65 5} F43 {65 6} Console_19 {65 7} Console_31 {65 8} Console_7 {65 9} Console_19 {65 10} F7 {65 11} F7 {65 12} Console_7 {65 13} Console_19 {65 14} F7 {65 15} F7 {65 16} F7 {65 17} F19 {65 18} Console_19 {65 19} Console_31 {65 20} F31 {65 21} F43 {65 22} Console_19 {65 23} Console_31 {65 24} Console_7 {65 25} Console_19 {65 26} F7 {65 27} F7 {65 28} Console_7 {65 29} Console_19 {65 30} F7 {65 31} F7 {65 32} F7 {65 33} F19 {65 34} Console_19 {65 35} Console_31 {65 36} F31 {65 37} F43 {65 38} Console_19 {65 39} Console_31 {65 40} Console_7 {65 41} Console_19 {65 42} F7 {65 43} F7 {65 44} Console_7 {65 45} Console_19 {65 46} F7 {65 47} F7 {65 48} F7 {65 49} F19 {65 50} Console_19 {65 51} Console_31 {65 52} F31 {65 53} F43 {65 54} Console_19 {65 55} Console_31 {65 56} Console_7 {65 57} Console_19 {65 58} F7 {65 59} F7 {65 60} Console_7 {65 61} Console_19 {65 62} F7 {65 63} F7 {65 64} F7 {65 65} F19 {65 66} Console_19 {65 67} Console_31 {65 68} F31 {65 69} F43 {65 70} Console_19 {65 71} Console_31 {65 72} Console_7 {65 73} Console_19 {65 74} F7 {65 75} F7 {65 76} Console_7 {65 77} Console_19 {65 78} F7 {65 79} F7 {65 80} F7 {65 81} F19 {65 82} Console_19 {65 83} Console_31 {65 84} F31 {65 85} F43 {65 86} Console_19 {65 87} Console_31 {65 88} Console_7 {65 89} Console_19 {65 90} F7 {65 91} F7 {65 92} Console_7 {65 93} Console_19 {65 94} F7 {65 95} F7 {65 96} F7 {65 97} F19 {65 98} Console_19 {65 99} Console_31 {65 100} F31 {65 101} F43 {65 102} Console_19 {65 103} Console_31 {65 104} Console_7 {65 105} Console_19 {65 106} F7 {65 107} F7 {65 108} Console_7 {65 109} Console_19 {65 110} F7 {65 111} F7 {65 112} F7 {65 113} F19 {65 114} Console_19 {65 115} Console_31 {65 116} F31 {65 117} F43 {65 118} Console_19 {65 119} Console_31 {65 120} Console_7 {65 121} Console_19 {65 122} F7 {65 123} F7 {65 124} Console_7 {65 125} Console_19 {65 126} F7 {65 127} F7 {66 0} F8 {66 1} F20 {66 2} Console_20 {66 3} Console_32 {66 4} F32 {66 5} F44 {66 6} Console_20 {66 7} Console_32 {66 8} Console_8 {66 9} Console_20 {66 10} F8 {66 11} F8 {66 12} Console_8 {66 13} Console_20 {66 14} F8 {66 15} F8 {66 16} F8 {66 17} F20 {66 18} Console_20 {66 19} Console_32 {66 20} F32 {66 21} F44 {66 22} Console_20 {66 23} Console_32 {66 24} Console_8 {66 25} Console_20 {66 26} F8 {66 27} F8 {66 28} Console_8 {66 29} Console_20 {66 30} F8 {66 31} F8 {66 32} F8 {66 33} F20 {66 34} Console_20 {66 35} Console_32 {66 36} F32 {66 37} F44 {66 38} Console_20 {66 39} Console_32 {66 40} Console_8 {66 41} Console_20 {66 42} F8 {66 43} F8 {66 44} Console_8 {66 45} Console_20 {66 46} F8 {66 47} F8 {66 48} F8 {66 49} F20 {66 50} Console_20 {66 51} Console_32 {66 52} F32 {66 53} F44 {66 54} Console_20 {66 55} Console_32 {66 56} Console_8 {66 57} Console_20 {66 58} F8 {66 59} F8 {66 60} Console_8 {66 61} Console_20 {66 62} F8 {66 63} F8 {66 64} F8 {66 65} F20 {66 66} Console_20 {66 67} Console_32 {66 68} F32 {66 69} F44 {66 70} Console_20 {66 71} Console_32 {66 72} Console_8 {66 73} Console_20 {66 74} F8 {66 75} F8 {66 76} Console_8 {66 77} Console_20 {66 78} F8 {66 79} F8 {66 80} F8 {66 81} F20 {66 82} Console_20 {66 83} Console_32 {66 84} F32 {66 85} F44 {66 86} Console_20 {66 87} Console_32 {66 88} Console_8 {66 89} Console_20 {66 90} F8 {66 91} F8 {66 92} Console_8 {66 93} Console_20 {66 94} F8 {66 95} F8 {66 96} F8 {66 97} F20 {66 98} Console_20 {66 99} Console_32 {66 100} F32 {66 101} F44 {66 102} Console_20 {66 103} Console_32 {66 104} Console_8 {66 105} Console_20 {66 106} F8 {66 107} F8 {66 108} Console_8 {66 109} Console_20 {66 110} F8 {66 111} F8 {66 112} F8 {66 113} F20 {66 114} Console_20 {66 115} Console_32 {66 116} F32 {66 117} F44 {66 118} Console_20 {66 119} Console_32 {66 120} Console_8 {66 121} Console_20 {66 122} F8 {66 123} F8 {66 124} Console_8 {66 125} Console_20 {66 126} F8 {66 127} F8 {67 0} F9 {67 1} F21 {67 2} Console_21 {67 3} Console_33 {67 4} F33 {67 5} F45 {67 6} Console_21 {67 7} Console_33 {67 8} Console_9 {67 9} Console_21 {67 10} F9 {67 11} F9 {67 12} Console_9 {67 13} Console_21 {67 14} F9 {67 15} F9 {67 16} F9 {67 17} F21 {67 18} Console_21 {67 19} Console_33 {67 20} F33 {67 21} F45 {67 22} Console_21 {67 23} Console_33 {67 24} Console_9 {67 25} Console_21 {67 26} F9 {67 27} F9 {67 28} Console_9 {67 29} Console_21 {67 30} F9 {67 31} F9 {67 32} F9 {67 33} F21 {67 34} Console_21 {67 35} Console_33 {67 36} F33 {67 37} F45 {67 38} Console_21 {67 39} Console_33 {67 40} Console_9 {67 41} Console_21 {67 42} F9 {67 43} F9 {67 44} Console_9 {67 45} Console_21 {67 46} F9 {67 47} F9 {67 48} F9 {67 49} F21 {67 50} Console_21 {67 51} Console_33 {67 52} F33 {67 53} F45 {67 54} Console_21 {67 55} Console_33 {67 56} Console_9 {67 57} Console_21 {67 58} F9 {67 59} F9 {67 60} Console_9 {67 61} Console_21 {67 62} F9 {67 63} F9 {67 64} F9 {67 65} F21 {67 66} Console_21 {67 67} Console_33 {67 68} F33 {67 69} F45 {67 70} Console_21 {67 71} Console_33 {67 72} Console_9 {67 73} Console_21 {67 74} F9 {67 75} F9 {67 76} Console_9 {67 77} Console_21 {67 78} F9 {67 79} F9 {67 80} F9 {67 81} F21 {67 82} Console_21 {67 83} Console_33 {67 84} F33 {67 85} F45 {67 86} Console_21 {67 87} Console_33 {67 88} Console_9 {67 89} Console_21 {67 90} F9 {67 91} F9 {67 92} Console_9 {67 93} Console_21 {67 94} F9 {67 95} F9 {67 96} F9 {67 97} F21 {67 98} Console_21 {67 99} Console_33 {67 100} F33 {67 101} F45 {67 102} Console_21 {67 103} Console_33 {67 104} Console_9 {67 105} Console_21 {67 106} F9 {67 107} F9 {67 108} Console_9 {67 109} Console_21 {67 110} F9 {67 111} F9 {67 112} F9 {67 113} F21 {67 114} Console_21 {67 115} Console_33 {67 116} F33 {67 117} F45 {67 118} Console_21 {67 119} Console_33 {67 120} Console_9 {67 121} Console_21 {67 122} F9 {67 123} F9 {67 124} Console_9 {67 125} Console_21 {67 126} F9 {67 127} F9 {68 0} F10 {68 1} F22 {68 2} Console_22 {68 3} Console_34 {68 4} F34 {68 5} F46 {68 6} Console_22 {68 7} Console_34 {68 8} Console_10 {68 9} Console_22 {68 10} F10 {68 11} F10 {68 12} Console_10 {68 13} Console_22 {68 14} F10 {68 15} F10 {68 16} F10 {68 17} F22 {68 18} Console_22 {68 19} Console_34 {68 20} F34 {68 21} F46 {68 22} Console_22 {68 23} Console_34 {68 24} Console_10 {68 25} Console_22 {68 26} F10 {68 27} F10 {68 28} Console_10 {68 29} Console_22 {68 30} F10 {68 31} F10 {68 32} F10 {68 33} F22 {68 34} Console_22 {68 35} Console_34 {68 36} F34 {68 37} F46 {68 38} Console_22 {68 39} Console_34 {68 40} Console_10 {68 41} Console_22 {68 42} F10 {68 43} F10 {68 44} Console_10 {68 45} Console_22 {68 46} F10 {68 47} F10 {68 48} F10 {68 49} F22 {68 50} Console_22 {68 51} Console_34 {68 52} F34 {68 53} F46 {68 54} Console_22 {68 55} Console_34 {68 56} Console_10 {68 57} Console_22 {68 58} F10 {68 59} F10 {68 60} Console_10 {68 61} Console_22 {68 62} F10 {68 63} F10 {68 64} F10 {68 65} F22 {68 66} Console_22 {68 67} Console_34 {68 68} F34 {68 69} F46 {68 70} Console_22 {68 71} Console_34 {68 72} Console_10 {68 73} Console_22 {68 74} F10 {68 75} F10 {68 76} Console_10 {68 77} Console_22 {68 78} F10 {68 79} F10 {68 80} F10 {68 81} F22 {68 82} Console_22 {68 83} Console_34 {68 84} F34 {68 85} F46 {68 86} Console_22 {68 87} Console_34 {68 88} Console_10 {68 89} Console_22 {68 90} F10 {68 91} F10 {68 92} Console_10 {68 93} Console_22 {68 94} F10 {68 95} F10 {68 96} F10 {68 97} F22 {68 98} Console_22 {68 99} Console_34 {68 100} F34 {68 101} F46 {68 102} Console_22 {68 103} Console_34 {68 104} Console_10 {68 105} Console_22 {68 106} F10 {68 107} F10 {68 108} Console_10 {68 109} Console_22 {68 110} F10 {68 111} F10 {68 112} F10 {68 113} F22 {68 114} Console_22 {68 115} Console_34 {68 116} F34 {68 117} F46 {68 118} Console_22 {68 119} Console_34 {68 120} Console_10 {68 121} Console_22 {68 122} F10 {68 123} F10 {68 124} Console_10 {68 125} Console_22 {68 126} F10 {68 127} F10 {69 0} Num_Lock {69 1} Num_Lock {69 2} Hex_A {69 3} Num_Lock {69 4} Num_Lock {69 5} Num_Lock {69 6} Num_Lock {69 7} Num_Lock {69 8} Num_Lock {69 9} Hex_A {69 10} Num_Lock {69 11} Num_Lock {69 12} Num_Lock {69 13} Num_Lock {69 14} Num_Lock {69 15} Num_Lock {69 16} Num_Lock {69 17} Num_Lock {69 18} Hex_A {69 19} Num_Lock {69 20} Num_Lock {69 21} Num_Lock {69 22} Num_Lock {69 23} Num_Lock {69 24} Num_Lock {69 25} Hex_A {69 26} Num_Lock {69 27} Num_Lock {69 28} Num_Lock {69 29} Num_Lock {69 30} Num_Lock {69 31} Num_Lock {69 32} Num_Lock {69 33} Num_Lock {69 34} Hex_A {69 35} Num_Lock {69 36} Num_Lock {69 37} Num_Lock {69 38} Num_Lock {69 39} Num_Lock {69 40} Num_Lock {69 41} Hex_A {69 42} Num_Lock {69 43} Num_Lock {69 44} Num_Lock {69 45} Num_Lock {69 46} Num_Lock {69 47} Num_Lock {69 48} Num_Lock {69 49} Num_Lock {69 50} Hex_A {69 51} Num_Lock {69 52} Num_Lock {69 53} Num_Lock {69 54} Num_Lock {69 55} Num_Lock {69 56} Num_Lock {69 57} Hex_A {69 58} Num_Lock {69 59} Num_Lock {69 60} Num_Lock {69 61} Num_Lock {69 62} Num_Lock {69 63} Num_Lock {69 64} Num_Lock {69 65} Num_Lock {69 66} Hex_A {69 67} Num_Lock {69 68} Num_Lock {69 69} Num_Lock {69 70} Num_Lock {69 71} Num_Lock {69 72} Num_Lock {69 73} Hex_A {69 74} Num_Lock {69 75} Num_Lock {69 76} Num_Lock {69 77} Num_Lock {69 78} Num_Lock {69 79} Num_Lock {69 80} Num_Lock {69 81} Num_Lock {69 82} Hex_A {69 83} Num_Lock {69 84} Num_Lock {69 85} Num_Lock {69 86} Num_Lock {69 87} Num_Lock {69 88} Num_Lock {69 89} Hex_A {69 90} Num_Lock {69 91} Num_Lock {69 92} Num_Lock {69 93} Num_Lock {69 94} Num_Lock {69 95} Num_Lock {69 96} Num_Lock {69 97} Num_Lock {69 98} Hex_A {69 99} Num_Lock {69 100} Num_Lock {69 101} Num_Lock {69 102} Num_Lock {69 103} Num_Lock {69 104} Num_Lock {69 105} Hex_A {69 106} Num_Lock {69 107} Num_Lock {69 108} Num_Lock {69 109} Num_Lock {69 110} Num_Lock {69 111} Num_Lock {69 112} Num_Lock {69 113} Num_Lock {69 114} Hex_A {69 115} Num_Lock {69 116} Num_Lock {69 117} Num_Lock {69 118} Num_Lock {69 119} Num_Lock {69 120} Num_Lock {69 121} Hex_A {69 122} Num_Lock {69 123} Num_Lock {69 124} Num_Lock {69 125} Num_Lock {69 126} Num_Lock {69 127} Num_Lock {70 0} Scroll_Lock {70 1} Show_Memory {70 2} Show_Registers {70 3} Scroll_Lock {70 4} Show_State {70 5} Scroll_Lock {70 6} Scroll_Lock {70 7} Scroll_Lock {70 8} Show_Registers {70 9} Scroll_Lock {70 10} Scroll_Lock {70 11} Scroll_Lock {70 12} Scroll_Lock {70 13} Scroll_Lock {70 14} Scroll_Lock {70 15} Scroll_Lock {70 16} Scroll_Lock {70 17} Show_Memory {70 18} Show_Registers {70 19} Scroll_Lock {70 20} Show_State {70 21} Scroll_Lock {70 22} Scroll_Lock {70 23} Scroll_Lock {70 24} Show_Registers {70 25} Scroll_Lock {70 26} Scroll_Lock {70 27} Scroll_Lock {70 28} Scroll_Lock {70 29} Scroll_Lock {70 30} Scroll_Lock {70 31} Scroll_Lock {70 32} Scroll_Lock {70 33} Show_Memory {70 34} Show_Registers {70 35} Scroll_Lock {70 36} Show_State {70 37} Scroll_Lock {70 38} Scroll_Lock {70 39} Scroll_Lock {70 40} Show_Registers {70 41} Scroll_Lock {70 42} Scroll_Lock {70 43} Scroll_Lock {70 44} Scroll_Lock {70 45} Scroll_Lock {70 46} Scroll_Lock {70 47} Scroll_Lock {70 48} Scroll_Lock {70 49} Show_Memory {70 50} Show_Registers {70 51} Scroll_Lock {70 52} Show_State {70 53} Scroll_Lock {70 54} Scroll_Lock {70 55} Scroll_Lock {70 56} Show_Registers {70 57} Scroll_Lock {70 58} Scroll_Lock {70 59} Scroll_Lock {70 60} Scroll_Lock {70 61} Scroll_Lock {70 62} Scroll_Lock {70 63} Scroll_Lock {70 64} Scroll_Lock {70 65} Show_Memory {70 66} Show_Registers {70 67} Scroll_Lock {70 68} Show_State {70 69} Scroll_Lock {70 70} Scroll_Lock {70 71} Scroll_Lock {70 72} Show_Registers {70 73} Scroll_Lock {70 74} Scroll_Lock {70 75} Scroll_Lock {70 76} Scroll_Lock {70 77} Scroll_Lock {70 78} Scroll_Lock {70 79} Scroll_Lock {70 80} Scroll_Lock {70 81} Show_Memory {70 82} Show_Registers {70 83} Scroll_Lock {70 84} Show_State {70 85} Scroll_Lock {70 86} Scroll_Lock {70 87} Scroll_Lock {70 88} Show_Registers {70 89} Scroll_Lock {70 90} Scroll_Lock {70 91} Scroll_Lock {70 92} Scroll_Lock {70 93} Scroll_Lock {70 94} Scroll_Lock {70 95} Scroll_Lock {70 96} Scroll_Lock {70 97} Show_Memory {70 98} Show_Registers {70 99} Scroll_Lock {70 100} Show_State {70 101} Scroll_Lock {70 102} Scroll_Lock {70 103} Scroll_Lock {70 104} Show_Registers {70 105} Scroll_Lock {70 106} Scroll_Lock {70 107} Scroll_Lock {70 108} Scroll_Lock {70 109} Scroll_Lock {70 110} Scroll_Lock {70 111} Scroll_Lock {70 112} Scroll_Lock {70 113} Show_Memory {70 114} Show_Registers {70 115} Scroll_Lock {70 116} Show_State {70 117} Scroll_Lock {70 118} Scroll_Lock {70 119} Scroll_Lock {70 120} Show_Registers {70 121} Scroll_Lock {70 122} Scroll_Lock {70 123} Scroll_Lock {70 124} Scroll_Lock {70 125} Scroll_Lock {70 126} Scroll_Lock {70 127} Scroll_Lock {71 0} KP_7 {71 1} KP_7 {71 2} Hex_7 {71 3} KP_7 {71 4} KP_7 {71 5} KP_7 {71 6} KP_7 {71 7} KP_7 {71 8} Ascii_7 {71 9} Hex_7 {71 10} KP_7 {71 11} KP_7 {71 12} KP_7 {71 13} KP_7 {71 14} KP_7 {71 15} KP_7 {71 16} KP_7 {71 17} KP_7 {71 18} Hex_7 {71 19} KP_7 {71 20} KP_7 {71 21} KP_7 {71 22} KP_7 {71 23} KP_7 {71 24} Ascii_7 {71 25} Hex_7 {71 26} KP_7 {71 27} KP_7 {71 28} KP_7 {71 29} KP_7 {71 30} KP_7 {71 31} KP_7 {71 32} KP_7 {71 33} KP_7 {71 34} Hex_7 {71 35} KP_7 {71 36} KP_7 {71 37} KP_7 {71 38} KP_7 {71 39} KP_7 {71 40} Ascii_7 {71 41} Hex_7 {71 42} KP_7 {71 43} KP_7 {71 44} KP_7 {71 45} KP_7 {71 46} KP_7 {71 47} KP_7 {71 48} KP_7 {71 49} KP_7 {71 50} Hex_7 {71 51} KP_7 {71 52} KP_7 {71 53} KP_7 {71 54} KP_7 {71 55} KP_7 {71 56} Ascii_7 {71 57} Hex_7 {71 58} KP_7 {71 59} KP_7 {71 60} KP_7 {71 61} KP_7 {71 62} KP_7 {71 63} KP_7 {71 64} KP_7 {71 65} KP_7 {71 66} Hex_7 {71 67} KP_7 {71 68} KP_7 {71 69} KP_7 {71 70} KP_7 {71 71} KP_7 {71 72} Ascii_7 {71 73} Hex_7 {71 74} KP_7 {71 75} KP_7 {71 76} KP_7 {71 77} KP_7 {71 78} KP_7 {71 79} KP_7 {71 80} KP_7 {71 81} KP_7 {71 82} Hex_7 {71 83} KP_7 {71 84} KP_7 {71 85} KP_7 {71 86} KP_7 {71 87} KP_7 {71 88} Ascii_7 {71 89} Hex_7 {71 90} KP_7 {71 91} KP_7 {71 92} KP_7 {71 93} KP_7 {71 94} KP_7 {71 95} KP_7 {71 96} KP_7 {71 97} KP_7 {71 98} Hex_7 {71 99} KP_7 {71 100} KP_7 {71 101} KP_7 {71 102} KP_7 {71 103} KP_7 {71 104} Ascii_7 {71 105} Hex_7 {71 106} KP_7 {71 107} KP_7 {71 108} KP_7 {71 109} KP_7 {71 110} KP_7 {71 111} KP_7 {71 112} KP_7 {71 113} KP_7 {71 114} Hex_7 {71 115} KP_7 {71 116} KP_7 {71 117} KP_7 {71 118} KP_7 {71 119} KP_7 {71 120} Ascii_7 {71 121} Hex_7 {71 122} KP_7 {71 123} KP_7 {71 124} KP_7 {71 125} KP_7 {71 126} KP_7 {71 127} KP_7 {72 0} KP_8 {72 1} KP_8 {72 2} Hex_8 {72 3} KP_8 {72 4} KP_8 {72 5} KP_8 {72 6} KP_8 {72 7} KP_8 {72 8} Ascii_8 {72 9} Hex_8 {72 10} KP_8 {72 11} KP_8 {72 12} KP_8 {72 13} KP_8 {72 14} KP_8 {72 15} KP_8 {72 16} KP_8 {72 17} KP_8 {72 18} Hex_8 {72 19} KP_8 {72 20} KP_8 {72 21} KP_8 {72 22} KP_8 {72 23} KP_8 {72 24} Ascii_8 {72 25} Hex_8 {72 26} KP_8 {72 27} KP_8 {72 28} KP_8 {72 29} KP_8 {72 30} KP_8 {72 31} KP_8 {72 32} KP_8 {72 33} KP_8 {72 34} Hex_8 {72 35} KP_8 {72 36} KP_8 {72 37} KP_8 {72 38} KP_8 {72 39} KP_8 {72 40} Ascii_8 {72 41} Hex_8 {72 42} KP_8 {72 43} KP_8 {72 44} KP_8 {72 45} KP_8 {72 46} KP_8 {72 47} KP_8 {72 48} KP_8 {72 49} KP_8 {72 50} Hex_8 {72 51} KP_8 {72 52} KP_8 {72 53} KP_8 {72 54} KP_8 {72 55} KP_8 {72 56} Ascii_8 {72 57} Hex_8 {72 58} KP_8 {72 59} KP_8 {72 60} KP_8 {72 61} KP_8 {72 62} KP_8 {72 63} KP_8 {72 64} KP_8 {72 65} KP_8 {72 66} Hex_8 {72 67} KP_8 {72 68} KP_8 {72 69} KP_8 {72 70} KP_8 {72 71} KP_8 {72 72} Ascii_8 {72 73} Hex_8 {72 74} KP_8 {72 75} KP_8 {72 76} KP_8 {72 77} KP_8 {72 78} KP_8 {72 79} KP_8 {72 80} KP_8 {72 81} KP_8 {72 82} Hex_8 {72 83} KP_8 {72 84} KP_8 {72 85} KP_8 {72 86} KP_8 {72 87} KP_8 {72 88} Ascii_8 {72 89} Hex_8 {72 90} KP_8 {72 91} KP_8 {72 92} KP_8 {72 93} KP_8 {72 94} KP_8 {72 95} KP_8 {72 96} KP_8 {72 97} KP_8 {72 98} Hex_8 {72 99} KP_8 {72 100} KP_8 {72 101} KP_8 {72 102} KP_8 {72 103} KP_8 {72 104} Ascii_8 {72 105} Hex_8 {72 106} KP_8 {72 107} KP_8 {72 108} KP_8 {72 109} KP_8 {72 110} KP_8 {72 111} KP_8 {72 112} KP_8 {72 113} KP_8 {72 114} Hex_8 {72 115} KP_8 {72 116} KP_8 {72 117} KP_8 {72 118} KP_8 {72 119} KP_8 {72 120} Ascii_8 {72 121} Hex_8 {72 122} KP_8 {72 123} KP_8 {72 124} KP_8 {72 125} KP_8 {72 126} KP_8 {72 127} KP_8 {73 0} KP_9 {73 1} KP_9 {73 2} Hex_9 {73 3} KP_9 {73 4} KP_9 {73 5} KP_9 {73 6} KP_9 {73 7} KP_9 {73 8} Ascii_9 {73 9} Hex_9 {73 10} KP_9 {73 11} KP_9 {73 12} KP_9 {73 13} KP_9 {73 14} KP_9 {73 15} KP_9 {73 16} KP_9 {73 17} KP_9 {73 18} Hex_9 {73 19} KP_9 {73 20} KP_9 {73 21} KP_9 {73 22} KP_9 {73 23} KP_9 {73 24} Ascii_9 {73 25} Hex_9 {73 26} KP_9 {73 27} KP_9 {73 28} KP_9 {73 29} KP_9 {73 30} KP_9 {73 31} KP_9 {73 32} KP_9 {73 33} KP_9 {73 34} Hex_9 {73 35} KP_9 {73 36} KP_9 {73 37} KP_9 {73 38} KP_9 {73 39} KP_9 {73 40} Ascii_9 {73 41} Hex_9 {73 42} KP_9 {73 43} KP_9 {73 44} KP_9 {73 45} KP_9 {73 46} KP_9 {73 47} KP_9 {73 48} KP_9 {73 49} KP_9 {73 50} Hex_9 {73 51} KP_9 {73 52} KP_9 {73 53} KP_9 {73 54} KP_9 {73 55} KP_9 {73 56} Ascii_9 {73 57} Hex_9 {73 58} KP_9 {73 59} KP_9 {73 60} KP_9 {73 61} KP_9 {73 62} KP_9 {73 63} KP_9 {73 64} KP_9 {73 65} KP_9 {73 66} Hex_9 {73 67} KP_9 {73 68} KP_9 {73 69} KP_9 {73 70} KP_9 {73 71} KP_9 {73 72} Ascii_9 {73 73} Hex_9 {73 74} KP_9 {73 75} KP_9 {73 76} KP_9 {73 77} KP_9 {73 78} KP_9 {73 79} KP_9 {73 80} KP_9 {73 81} KP_9 {73 82} Hex_9 {73 83} KP_9 {73 84} KP_9 {73 85} KP_9 {73 86} KP_9 {73 87} KP_9 {73 88} Ascii_9 {73 89} Hex_9 {73 90} KP_9 {73 91} KP_9 {73 92} KP_9 {73 93} KP_9 {73 94} KP_9 {73 95} KP_9 {73 96} KP_9 {73 97} KP_9 {73 98} Hex_9 {73 99} KP_9 {73 100} KP_9 {73 101} KP_9 {73 102} KP_9 {73 103} KP_9 {73 104} Ascii_9 {73 105} Hex_9 {73 106} KP_9 {73 107} KP_9 {73 108} KP_9 {73 109} KP_9 {73 110} KP_9 {73 111} KP_9 {73 112} KP_9 {73 113} KP_9 {73 114} Hex_9 {73 115} KP_9 {73 116} KP_9 {73 117} KP_9 {73 118} KP_9 {73 119} KP_9 {73 120} Ascii_9 {73 121} Hex_9 {73 122} KP_9 {73 123} KP_9 {73 124} KP_9 {73 125} KP_9 {73 126} KP_9 {73 127} KP_9 {74 0} KP_Subtract {74 1} KP_Subtract {74 2} Hex_D {74 3} KP_Subtract {74 4} KP_Subtract {74 5} KP_Subtract {74 6} KP_Subtract {74 7} KP_Subtract {74 8} KP_Subtract {74 9} Hex_D {74 10} KP_Subtract {74 11} KP_Subtract {74 12} KP_Subtract {74 13} KP_Subtract {74 14} KP_Subtract {74 15} KP_Subtract {74 16} KP_Subtract {74 17} KP_Subtract {74 18} Hex_D {74 19} KP_Subtract {74 20} KP_Subtract {74 21} KP_Subtract {74 22} KP_Subtract {74 23} KP_Subtract {74 24} KP_Subtract {74 25} Hex_D {74 26} KP_Subtract {74 27} KP_Subtract {74 28} KP_Subtract {74 29} KP_Subtract {74 30} KP_Subtract {74 31} KP_Subtract {74 32} KP_Subtract {74 33} KP_Subtract {74 34} Hex_D {74 35} KP_Subtract {74 36} KP_Subtract {74 37} KP_Subtract {74 38} KP_Subtract {74 39} KP_Subtract {74 40} KP_Subtract {74 41} Hex_D {74 42} KP_Subtract {74 43} KP_Subtract {74 44} KP_Subtract {74 45} KP_Subtract {74 46} KP_Subtract {74 47} KP_Subtract {74 48} KP_Subtract {74 49} KP_Subtract {74 50} Hex_D {74 51} KP_Subtract {74 52} KP_Subtract {74 53} KP_Subtract {74 54} KP_Subtract {74 55} KP_Subtract {74 56} KP_Subtract {74 57} Hex_D {74 58} KP_Subtract {74 59} KP_Subtract {74 60} KP_Subtract {74 61} KP_Subtract {74 62} KP_Subtract {74 63} KP_Subtract {74 64} KP_Subtract {74 65} KP_Subtract {74 66} Hex_D {74 67} KP_Subtract {74 68} KP_Subtract {74 69} KP_Subtract {74 70} KP_Subtract {74 71} KP_Subtract {74 72} KP_Subtract {74 73} Hex_D {74 74} KP_Subtract {74 75} KP_Subtract {74 76} KP_Subtract {74 77} KP_Subtract {74 78} KP_Subtract {74 79} KP_Subtract {74 80} KP_Subtract {74 81} KP_Subtract {74 82} Hex_D {74 83} KP_Subtract {74 84} KP_Subtract {74 85} KP_Subtract {74 86} KP_Subtract {74 87} KP_Subtract {74 88} KP_Subtract {74 89} Hex_D {74 90} KP_Subtract {74 91} KP_Subtract {74 92} KP_Subtract {74 93} KP_Subtract {74 94} KP_Subtract {74 95} KP_Subtract {74 96} KP_Subtract {74 97} KP_Subtract {74 98} Hex_D {74 99} KP_Subtract {74 100} KP_Subtract {74 101} KP_Subtract {74 102} KP_Subtract {74 103} KP_Subtract {74 104} KP_Subtract {74 105} Hex_D {74 106} KP_Subtract {74 107} KP_Subtract {74 108} KP_Subtract {74 109} KP_Subtract {74 110} KP_Subtract {74 111} KP_Subtract {74 112} KP_Subtract {74 113} KP_Subtract {74 114} Hex_D {74 115} KP_Subtract {74 116} KP_Subtract {74 117} KP_Subtract {74 118} KP_Subtract {74 119} KP_Subtract {74 120} KP_Subtract {74 121} Hex_D {74 122} KP_Subtract {74 123} KP_Subtract {74 124} KP_Subtract {74 125} KP_Subtract {74 126} KP_Subtract {74 127} KP_Subtract {75 0} KP_4 {75 1} KP_4 {75 2} Hex_4 {75 3} KP_4 {75 4} KP_4 {75 5} KP_4 {75 6} KP_4 {75 7} KP_4 {75 8} Ascii_4 {75 9} Hex_4 {75 10} KP_4 {75 11} KP_4 {75 12} KP_4 {75 13} KP_4 {75 14} KP_4 {75 15} KP_4 {75 16} KP_4 {75 17} KP_4 {75 18} Hex_4 {75 19} KP_4 {75 20} KP_4 {75 21} KP_4 {75 22} KP_4 {75 23} KP_4 {75 24} Ascii_4 {75 25} Hex_4 {75 26} KP_4 {75 27} KP_4 {75 28} KP_4 {75 29} KP_4 {75 30} KP_4 {75 31} KP_4 {75 32} KP_4 {75 33} KP_4 {75 34} Hex_4 {75 35} KP_4 {75 36} KP_4 {75 37} KP_4 {75 38} KP_4 {75 39} KP_4 {75 40} Ascii_4 {75 41} Hex_4 {75 42} KP_4 {75 43} KP_4 {75 44} KP_4 {75 45} KP_4 {75 46} KP_4 {75 47} KP_4 {75 48} KP_4 {75 49} KP_4 {75 50} Hex_4 {75 51} KP_4 {75 52} KP_4 {75 53} KP_4 {75 54} KP_4 {75 55} KP_4 {75 56} Ascii_4 {75 57} Hex_4 {75 58} KP_4 {75 59} KP_4 {75 60} KP_4 {75 61} KP_4 {75 62} KP_4 {75 63} KP_4 {75 64} KP_4 {75 65} KP_4 {75 66} Hex_4 {75 67} KP_4 {75 68} KP_4 {75 69} KP_4 {75 70} KP_4 {75 71} KP_4 {75 72} Ascii_4 {75 73} Hex_4 {75 74} KP_4 {75 75} KP_4 {75 76} KP_4 {75 77} KP_4 {75 78} KP_4 {75 79} KP_4 {75 80} KP_4 {75 81} KP_4 {75 82} Hex_4 {75 83} KP_4 {75 84} KP_4 {75 85} KP_4 {75 86} KP_4 {75 87} KP_4 {75 88} Ascii_4 {75 89} Hex_4 {75 90} KP_4 {75 91} KP_4 {75 92} KP_4 {75 93} KP_4 {75 94} KP_4 {75 95} KP_4 {75 96} KP_4 {75 97} KP_4 {75 98} Hex_4 {75 99} KP_4 {75 100} KP_4 {75 101} KP_4 {75 102} KP_4 {75 103} KP_4 {75 104} Ascii_4 {75 105} Hex_4 {75 106} KP_4 {75 107} KP_4 {75 108} KP_4 {75 109} KP_4 {75 110} KP_4 {75 111} KP_4 {75 112} KP_4 {75 113} KP_4 {75 114} Hex_4 {75 115} KP_4 {75 116} KP_4 {75 117} KP_4 {75 118} KP_4 {75 119} KP_4 {75 120} Ascii_4 {75 121} Hex_4 {75 122} KP_4 {75 123} KP_4 {75 124} KP_4 {75 125} KP_4 {75 126} KP_4 {75 127} KP_4 {76 0} KP_5 {76 1} KP_5 {76 2} Hex_5 {76 3} KP_5 {76 4} KP_5 {76 5} KP_5 {76 6} KP_5 {76 7} KP_5 {76 8} Ascii_5 {76 9} Hex_5 {76 10} KP_5 {76 11} KP_5 {76 12} KP_5 {76 13} KP_5 {76 14} KP_5 {76 15} KP_5 {76 16} KP_5 {76 17} KP_5 {76 18} Hex_5 {76 19} KP_5 {76 20} KP_5 {76 21} KP_5 {76 22} KP_5 {76 23} KP_5 {76 24} Ascii_5 {76 25} Hex_5 {76 26} KP_5 {76 27} KP_5 {76 28} KP_5 {76 29} KP_5 {76 30} KP_5 {76 31} KP_5 {76 32} KP_5 {76 33} KP_5 {76 34} Hex_5 {76 35} KP_5 {76 36} KP_5 {76 37} KP_5 {76 38} KP_5 {76 39} KP_5 {76 40} Ascii_5 {76 41} Hex_5 {76 42} KP_5 {76 43} KP_5 {76 44} KP_5 {76 45} KP_5 {76 46} KP_5 {76 47} KP_5 {76 48} KP_5 {76 49} KP_5 {76 50} Hex_5 {76 51} KP_5 {76 52} KP_5 {76 53} KP_5 {76 54} KP_5 {76 55} KP_5 {76 56} Ascii_5 {76 57} Hex_5 {76 58} KP_5 {76 59} KP_5 {76 60} KP_5 {76 61} KP_5 {76 62} KP_5 {76 63} KP_5 {76 64} KP_5 {76 65} KP_5 {76 66} Hex_5 {76 67} KP_5 {76 68} KP_5 {76 69} KP_5 {76 70} KP_5 {76 71} KP_5 {76 72} Ascii_5 {76 73} Hex_5 {76 74} KP_5 {76 75} KP_5 {76 76} KP_5 {76 77} KP_5 {76 78} KP_5 {76 79} KP_5 {76 80} KP_5 {76 81} KP_5 {76 82} Hex_5 {76 83} KP_5 {76 84} KP_5 {76 85} KP_5 {76 86} KP_5 {76 87} KP_5 {76 88} Ascii_5 {76 89} Hex_5 {76 90} KP_5 {76 91} KP_5 {76 92} KP_5 {76 93} KP_5 {76 94} KP_5 {76 95} KP_5 {76 96} KP_5 {76 97} KP_5 {76 98} Hex_5 {76 99} KP_5 {76 100} KP_5 {76 101} KP_5 {76 102} KP_5 {76 103} KP_5 {76 104} Ascii_5 {76 105} Hex_5 {76 106} KP_5 {76 107} KP_5 {76 108} KP_5 {76 109} KP_5 {76 110} KP_5 {76 111} KP_5 {76 112} KP_5 {76 113} KP_5 {76 114} Hex_5 {76 115} KP_5 {76 116} KP_5 {76 117} KP_5 {76 118} KP_5 {76 119} KP_5 {76 120} Ascii_5 {76 121} Hex_5 {76 122} KP_5 {76 123} KP_5 {76 124} KP_5 {76 125} KP_5 {76 126} KP_5 {76 127} KP_5 {77 0} KP_6 {77 1} KP_6 {77 2} Hex_6 {77 3} KP_6 {77 4} KP_6 {77 5} KP_6 {77 6} KP_6 {77 7} KP_6 {77 8} Ascii_6 {77 9} Hex_6 {77 10} KP_6 {77 11} KP_6 {77 12} KP_6 {77 13} KP_6 {77 14} KP_6 {77 15} KP_6 {77 16} KP_6 {77 17} KP_6 {77 18} Hex_6 {77 19} KP_6 {77 20} KP_6 {77 21} KP_6 {77 22} KP_6 {77 23} KP_6 {77 24} Ascii_6 {77 25} Hex_6 {77 26} KP_6 {77 27} KP_6 {77 28} KP_6 {77 29} KP_6 {77 30} KP_6 {77 31} KP_6 {77 32} KP_6 {77 33} KP_6 {77 34} Hex_6 {77 35} KP_6 {77 36} KP_6 {77 37} KP_6 {77 38} KP_6 {77 39} KP_6 {77 40} Ascii_6 {77 41} Hex_6 {77 42} KP_6 {77 43} KP_6 {77 44} KP_6 {77 45} KP_6 {77 46} KP_6 {77 47} KP_6 {77 48} KP_6 {77 49} KP_6 {77 50} Hex_6 {77 51} KP_6 {77 52} KP_6 {77 53} KP_6 {77 54} KP_6 {77 55} KP_6 {77 56} Ascii_6 {77 57} Hex_6 {77 58} KP_6 {77 59} KP_6 {77 60} KP_6 {77 61} KP_6 {77 62} KP_6 {77 63} KP_6 {77 64} KP_6 {77 65} KP_6 {77 66} Hex_6 {77 67} KP_6 {77 68} KP_6 {77 69} KP_6 {77 70} KP_6 {77 71} KP_6 {77 72} Ascii_6 {77 73} Hex_6 {77 74} KP_6 {77 75} KP_6 {77 76} KP_6 {77 77} KP_6 {77 78} KP_6 {77 79} KP_6 {77 80} KP_6 {77 81} KP_6 {77 82} Hex_6 {77 83} KP_6 {77 84} KP_6 {77 85} KP_6 {77 86} KP_6 {77 87} KP_6 {77 88} Ascii_6 {77 89} Hex_6 {77 90} KP_6 {77 91} KP_6 {77 92} KP_6 {77 93} KP_6 {77 94} KP_6 {77 95} KP_6 {77 96} KP_6 {77 97} KP_6 {77 98} Hex_6 {77 99} KP_6 {77 100} KP_6 {77 101} KP_6 {77 102} KP_6 {77 103} KP_6 {77 104} Ascii_6 {77 105} Hex_6 {77 106} KP_6 {77 107} KP_6 {77 108} KP_6 {77 109} KP_6 {77 110} KP_6 {77 111} KP_6 {77 112} KP_6 {77 113} KP_6 {77 114} Hex_6 {77 115} KP_6 {77 116} KP_6 {77 117} KP_6 {77 118} KP_6 {77 119} KP_6 {77 120} Ascii_6 {77 121} Hex_6 {77 122} KP_6 {77 123} KP_6 {77 124} KP_6 {77 125} KP_6 {77 126} KP_6 {77 127} KP_6 {78 0} KP_Add {78 1} KP_Add {78 2} Hex_E {78 3} KP_Add {78 4} KP_Add {78 5} KP_Add {78 6} KP_Add {78 7} KP_Add {78 8} KP_Add {78 9} Hex_E {78 10} KP_Add {78 11} KP_Add {78 12} KP_Add {78 13} KP_Add {78 14} KP_Add {78 15} KP_Add {78 16} KP_Add {78 17} KP_Add {78 18} Hex_E {78 19} KP_Add {78 20} KP_Add {78 21} KP_Add {78 22} KP_Add {78 23} KP_Add {78 24} KP_Add {78 25} Hex_E {78 26} KP_Add {78 27} KP_Add {78 28} KP_Add {78 29} KP_Add {78 30} KP_Add {78 31} KP_Add {78 32} KP_Add {78 33} KP_Add {78 34} Hex_E {78 35} KP_Add {78 36} KP_Add {78 37} KP_Add {78 38} KP_Add {78 39} KP_Add {78 40} KP_Add {78 41} Hex_E {78 42} KP_Add {78 43} KP_Add {78 44} KP_Add {78 45} KP_Add {78 46} KP_Add {78 47} KP_Add {78 48} KP_Add {78 49} KP_Add {78 50} Hex_E {78 51} KP_Add {78 52} KP_Add {78 53} KP_Add {78 54} KP_Add {78 55} KP_Add {78 56} KP_Add {78 57} Hex_E {78 58} KP_Add {78 59} KP_Add {78 60} KP_Add {78 61} KP_Add {78 62} KP_Add {78 63} KP_Add {78 64} KP_Add {78 65} KP_Add {78 66} Hex_E {78 67} KP_Add {78 68} KP_Add {78 69} KP_Add {78 70} KP_Add {78 71} KP_Add {78 72} KP_Add {78 73} Hex_E {78 74} KP_Add {78 75} KP_Add {78 76} KP_Add {78 77} KP_Add {78 78} KP_Add {78 79} KP_Add {78 80} KP_Add {78 81} KP_Add {78 82} Hex_E {78 83} KP_Add {78 84} KP_Add {78 85} KP_Add {78 86} KP_Add {78 87} KP_Add {78 88} KP_Add {78 89} Hex_E {78 90} KP_Add {78 91} KP_Add {78 92} KP_Add {78 93} KP_Add {78 94} KP_Add {78 95} KP_Add {78 96} KP_Add {78 97} KP_Add {78 98} Hex_E {78 99} KP_Add {78 100} KP_Add {78 101} KP_Add {78 102} KP_Add {78 103} KP_Add {78 104} KP_Add {78 105} Hex_E {78 106} KP_Add {78 107} KP_Add {78 108} KP_Add {78 109} KP_Add {78 110} KP_Add {78 111} KP_Add {78 112} KP_Add {78 113} KP_Add {78 114} Hex_E {78 115} KP_Add {78 116} KP_Add {78 117} KP_Add {78 118} KP_Add {78 119} KP_Add {78 120} KP_Add {78 121} Hex_E {78 122} KP_Add {78 123} KP_Add {78 124} KP_Add {78 125} KP_Add {78 126} KP_Add {78 127} KP_Add {79 0} KP_1 {79 1} KP_1 {79 2} Hex_1 {79 3} KP_1 {79 4} KP_1 {79 5} KP_1 {79 6} KP_1 {79 7} KP_1 {79 8} Ascii_1 {79 9} Hex_1 {79 10} KP_1 {79 11} KP_1 {79 12} KP_1 {79 13} KP_1 {79 14} KP_1 {79 15} KP_1 {79 16} KP_1 {79 17} KP_1 {79 18} Hex_1 {79 19} KP_1 {79 20} KP_1 {79 21} KP_1 {79 22} KP_1 {79 23} KP_1 {79 24} Ascii_1 {79 25} Hex_1 {79 26} KP_1 {79 27} KP_1 {79 28} KP_1 {79 29} KP_1 {79 30} KP_1 {79 31} KP_1 {79 32} KP_1 {79 33} KP_1 {79 34} Hex_1 {79 35} KP_1 {79 36} KP_1 {79 37} KP_1 {79 38} KP_1 {79 39} KP_1 {79 40} Ascii_1 {79 41} Hex_1 {79 42} KP_1 {79 43} KP_1 {79 44} KP_1 {79 45} KP_1 {79 46} KP_1 {79 47} KP_1 {79 48} KP_1 {79 49} KP_1 {79 50} Hex_1 {79 51} KP_1 {79 52} KP_1 {79 53} KP_1 {79 54} KP_1 {79 55} KP_1 {79 56} Ascii_1 {79 57} Hex_1 {79 58} KP_1 {79 59} KP_1 {79 60} KP_1 {79 61} KP_1 {79 62} KP_1 {79 63} KP_1 {79 64} KP_1 {79 65} KP_1 {79 66} Hex_1 {79 67} KP_1 {79 68} KP_1 {79 69} KP_1 {79 70} KP_1 {79 71} KP_1 {79 72} Ascii_1 {79 73} Hex_1 {79 74} KP_1 {79 75} KP_1 {79 76} KP_1 {79 77} KP_1 {79 78} KP_1 {79 79} KP_1 {79 80} KP_1 {79 81} KP_1 {79 82} Hex_1 {79 83} KP_1 {79 84} KP_1 {79 85} KP_1 {79 86} KP_1 {79 87} KP_1 {79 88} Ascii_1 {79 89} Hex_1 {79 90} KP_1 {79 91} KP_1 {79 92} KP_1 {79 93} KP_1 {79 94} KP_1 {79 95} KP_1 {79 96} KP_1 {79 97} KP_1 {79 98} Hex_1 {79 99} KP_1 {79 100} KP_1 {79 101} KP_1 {79 102} KP_1 {79 103} KP_1 {79 104} Ascii_1 {79 105} Hex_1 {79 106} KP_1 {79 107} KP_1 {79 108} KP_1 {79 109} KP_1 {79 110} KP_1 {79 111} KP_1 {79 112} KP_1 {79 113} KP_1 {79 114} Hex_1 {79 115} KP_1 {79 116} KP_1 {79 117} KP_1 {79 118} KP_1 {79 119} KP_1 {79 120} Ascii_1 {79 121} Hex_1 {79 122} KP_1 {79 123} KP_1 {79 124} KP_1 {79 125} KP_1 {79 126} KP_1 {79 127} KP_1 {80 0} KP_2 {80 1} KP_2 {80 2} Hex_2 {80 3} KP_2 {80 4} KP_2 {80 5} KP_2 {80 6} KP_2 {80 7} KP_2 {80 8} Ascii_2 {80 9} Hex_2 {80 10} KP_2 {80 11} KP_2 {80 12} KP_2 {80 13} KP_2 {80 14} KP_2 {80 15} KP_2 {80 16} KP_2 {80 17} KP_2 {80 18} Hex_2 {80 19} KP_2 {80 20} KP_2 {80 21} KP_2 {80 22} KP_2 {80 23} KP_2 {80 24} Ascii_2 {80 25} Hex_2 {80 26} KP_2 {80 27} KP_2 {80 28} KP_2 {80 29} KP_2 {80 30} KP_2 {80 31} KP_2 {80 32} KP_2 {80 33} KP_2 {80 34} Hex_2 {80 35} KP_2 {80 36} KP_2 {80 37} KP_2 {80 38} KP_2 {80 39} KP_2 {80 40} Ascii_2 {80 41} Hex_2 {80 42} KP_2 {80 43} KP_2 {80 44} KP_2 {80 45} KP_2 {80 46} KP_2 {80 47} KP_2 {80 48} KP_2 {80 49} KP_2 {80 50} Hex_2 {80 51} KP_2 {80 52} KP_2 {80 53} KP_2 {80 54} KP_2 {80 55} KP_2 {80 56} Ascii_2 {80 57} Hex_2 {80 58} KP_2 {80 59} KP_2 {80 60} KP_2 {80 61} KP_2 {80 62} KP_2 {80 63} KP_2 {80 64} KP_2 {80 65} KP_2 {80 66} Hex_2 {80 67} KP_2 {80 68} KP_2 {80 69} KP_2 {80 70} KP_2 {80 71} KP_2 {80 72} Ascii_2 {80 73} Hex_2 {80 74} KP_2 {80 75} KP_2 {80 76} KP_2 {80 77} KP_2 {80 78} KP_2 {80 79} KP_2 {80 80} KP_2 {80 81} KP_2 {80 82} Hex_2 {80 83} KP_2 {80 84} KP_2 {80 85} KP_2 {80 86} KP_2 {80 87} KP_2 {80 88} Ascii_2 {80 89} Hex_2 {80 90} KP_2 {80 91} KP_2 {80 92} KP_2 {80 93} KP_2 {80 94} KP_2 {80 95} KP_2 {80 96} KP_2 {80 97} KP_2 {80 98} Hex_2 {80 99} KP_2 {80 100} KP_2 {80 101} KP_2 {80 102} KP_2 {80 103} KP_2 {80 104} Ascii_2 {80 105} Hex_2 {80 106} KP_2 {80 107} KP_2 {80 108} KP_2 {80 109} KP_2 {80 110} KP_2 {80 111} KP_2 {80 112} KP_2 {80 113} KP_2 {80 114} Hex_2 {80 115} KP_2 {80 116} KP_2 {80 117} KP_2 {80 118} KP_2 {80 119} KP_2 {80 120} Ascii_2 {80 121} Hex_2 {80 122} KP_2 {80 123} KP_2 {80 124} KP_2 {80 125} KP_2 {80 126} KP_2 {80 127} KP_2 {81 0} KP_3 {81 1} KP_3 {81 2} Hex_3 {81 3} KP_3 {81 4} KP_3 {81 5} KP_3 {81 6} KP_3 {81 7} KP_3 {81 8} Ascii_3 {81 9} Hex_3 {81 10} KP_3 {81 11} KP_3 {81 12} KP_3 {81 13} KP_3 {81 14} KP_3 {81 15} KP_3 {81 16} KP_3 {81 17} KP_3 {81 18} Hex_3 {81 19} KP_3 {81 20} KP_3 {81 21} KP_3 {81 22} KP_3 {81 23} KP_3 {81 24} Ascii_3 {81 25} Hex_3 {81 26} KP_3 {81 27} KP_3 {81 28} KP_3 {81 29} KP_3 {81 30} KP_3 {81 31} KP_3 {81 32} KP_3 {81 33} KP_3 {81 34} Hex_3 {81 35} KP_3 {81 36} KP_3 {81 37} KP_3 {81 38} KP_3 {81 39} KP_3 {81 40} Ascii_3 {81 41} Hex_3 {81 42} KP_3 {81 43} KP_3 {81 44} KP_3 {81 45} KP_3 {81 46} KP_3 {81 47} KP_3 {81 48} KP_3 {81 49} KP_3 {81 50} Hex_3 {81 51} KP_3 {81 52} KP_3 {81 53} KP_3 {81 54} KP_3 {81 55} KP_3 {81 56} Ascii_3 {81 57} Hex_3 {81 58} KP_3 {81 59} KP_3 {81 60} KP_3 {81 61} KP_3 {81 62} KP_3 {81 63} KP_3 {81 64} KP_3 {81 65} KP_3 {81 66} Hex_3 {81 67} KP_3 {81 68} KP_3 {81 69} KP_3 {81 70} KP_3 {81 71} KP_3 {81 72} Ascii_3 {81 73} Hex_3 {81 74} KP_3 {81 75} KP_3 {81 76} KP_3 {81 77} KP_3 {81 78} KP_3 {81 79} KP_3 {81 80} KP_3 {81 81} KP_3 {81 82} Hex_3 {81 83} KP_3 {81 84} KP_3 {81 85} KP_3 {81 86} KP_3 {81 87} KP_3 {81 88} Ascii_3 {81 89} Hex_3 {81 90} KP_3 {81 91} KP_3 {81 92} KP_3 {81 93} KP_3 {81 94} KP_3 {81 95} KP_3 {81 96} KP_3 {81 97} KP_3 {81 98} Hex_3 {81 99} KP_3 {81 100} KP_3 {81 101} KP_3 {81 102} KP_3 {81 103} KP_3 {81 104} Ascii_3 {81 105} Hex_3 {81 106} KP_3 {81 107} KP_3 {81 108} KP_3 {81 109} KP_3 {81 110} KP_3 {81 111} KP_3 {81 112} KP_3 {81 113} KP_3 {81 114} Hex_3 {81 115} KP_3 {81 116} KP_3 {81 117} KP_3 {81 118} KP_3 {81 119} KP_3 {81 120} Ascii_3 {81 121} Hex_3 {81 122} KP_3 {81 123} KP_3 {81 124} KP_3 {81 125} KP_3 {81 126} KP_3 {81 127} KP_3 {82 0} KP_0 {82 1} KP_0 {82 2} Hex_0 {82 3} KP_0 {82 4} KP_0 {82 5} KP_0 {82 6} KP_0 {82 7} KP_0 {82 8} Ascii_0 {82 9} Hex_0 {82 10} KP_0 {82 11} KP_0 {82 12} KP_0 {82 13} KP_0 {82 14} KP_0 {82 15} KP_0 {82 16} KP_0 {82 17} KP_0 {82 18} Hex_0 {82 19} KP_0 {82 20} KP_0 {82 21} KP_0 {82 22} KP_0 {82 23} KP_0 {82 24} Ascii_0 {82 25} Hex_0 {82 26} KP_0 {82 27} KP_0 {82 28} KP_0 {82 29} KP_0 {82 30} KP_0 {82 31} KP_0 {82 32} KP_0 {82 33} KP_0 {82 34} Hex_0 {82 35} KP_0 {82 36} KP_0 {82 37} KP_0 {82 38} KP_0 {82 39} KP_0 {82 40} Ascii_0 {82 41} Hex_0 {82 42} KP_0 {82 43} KP_0 {82 44} KP_0 {82 45} KP_0 {82 46} KP_0 {82 47} KP_0 {82 48} KP_0 {82 49} KP_0 {82 50} Hex_0 {82 51} KP_0 {82 52} KP_0 {82 53} KP_0 {82 54} KP_0 {82 55} KP_0 {82 56} Ascii_0 {82 57} Hex_0 {82 58} KP_0 {82 59} KP_0 {82 60} KP_0 {82 61} KP_0 {82 62} KP_0 {82 63} KP_0 {82 64} KP_0 {82 65} KP_0 {82 66} Hex_0 {82 67} KP_0 {82 68} KP_0 {82 69} KP_0 {82 70} KP_0 {82 71} KP_0 {82 72} Ascii_0 {82 73} Hex_0 {82 74} KP_0 {82 75} KP_0 {82 76} KP_0 {82 77} KP_0 {82 78} KP_0 {82 79} KP_0 {82 80} KP_0 {82 81} KP_0 {82 82} Hex_0 {82 83} KP_0 {82 84} KP_0 {82 85} KP_0 {82 86} KP_0 {82 87} KP_0 {82 88} Ascii_0 {82 89} Hex_0 {82 90} KP_0 {82 91} KP_0 {82 92} KP_0 {82 93} KP_0 {82 94} KP_0 {82 95} KP_0 {82 96} KP_0 {82 97} KP_0 {82 98} Hex_0 {82 99} KP_0 {82 100} KP_0 {82 101} KP_0 {82 102} KP_0 {82 103} KP_0 {82 104} Ascii_0 {82 105} Hex_0 {82 106} KP_0 {82 107} KP_0 {82 108} KP_0 {82 109} KP_0 {82 110} KP_0 {82 111} KP_0 {82 112} KP_0 {82 113} KP_0 {82 114} Hex_0 {82 115} KP_0 {82 116} KP_0 {82 117} KP_0 {82 118} KP_0 {82 119} KP_0 {82 120} Ascii_0 {82 121} Hex_0 {82 122} KP_0 {82 123} KP_0 {82 124} KP_0 {82 125} KP_0 {82 126} KP_0 {82 127} KP_0 {83 0} KP_Period {83 1} KP_Period {83 2} KP_Period {83 3} KP_Period {83 4} KP_Period {83 5} KP_Period {83 6} Boot {83 7} KP_Period {83 8} KP_Period {83 9} KP_Period {83 10} KP_Period {83 11} KP_Period {83 12} Boot {83 13} KP_Period {83 14} Boot {83 15} KP_Period {83 16} KP_Period {83 17} KP_Period {83 18} KP_Period {83 19} KP_Period {83 20} KP_Period {83 21} KP_Period {83 22} Boot {83 23} KP_Period {83 24} KP_Period {83 25} KP_Period {83 26} KP_Period {83 27} KP_Period {83 28} Boot {83 29} KP_Period {83 30} Boot {83 31} KP_Period {83 32} KP_Period {83 33} KP_Period {83 34} KP_Period {83 35} KP_Period {83 36} KP_Period {83 37} KP_Period {83 38} Boot {83 39} KP_Period {83 40} KP_Period {83 41} KP_Period {83 42} KP_Period {83 43} KP_Period {83 44} Boot {83 45} KP_Period {83 46} Boot {83 47} KP_Period {83 48} KP_Period {83 49} KP_Period {83 50} KP_Period {83 51} KP_Period {83 52} KP_Period {83 53} KP_Period {83 54} Boot {83 55} KP_Period {83 56} KP_Period {83 57} KP_Period {83 58} KP_Period {83 59} KP_Period {83 60} Boot {83 61} KP_Period {83 62} Boot {83 63} KP_Period {83 64} KP_Period {83 65} KP_Period {83 66} KP_Period {83 67} KP_Period {83 68} KP_Period {83 69} KP_Period {83 70} Boot {83 71} KP_Period {83 72} KP_Period {83 73} KP_Period {83 74} KP_Period {83 75} KP_Period {83 76} Boot {83 77} KP_Period {83 78} Boot {83 79} KP_Period {83 80} KP_Period {83 81} KP_Period {83 82} KP_Period {83 83} KP_Period {83 84} KP_Period {83 85} KP_Period {83 86} Boot {83 87} KP_Period {83 88} KP_Period {83 89} KP_Period {83 90} KP_Period {83 91} KP_Period {83 92} Boot {83 93} KP_Period {83 94} Boot {83 95} KP_Period {83 96} KP_Period {83 97} KP_Period {83 98} KP_Period {83 99} KP_Period {83 100} KP_Period {83 101} KP_Period {83 102} Boot {83 103} KP_Period {83 104} KP_Period {83 105} KP_Period {83 106} KP_Period {83 107} KP_Period {83 108} Boot {83 109} KP_Period {83 110} Boot {83 111} KP_Period {83 112} KP_Period {83 113} KP_Period {83 114} KP_Period {83 115} KP_Period {83 116} KP_Period {83 117} KP_Period {83 118} Boot {83 119} KP_Period {83 120} KP_Period {83 121} KP_Period {83 122} KP_Period {83 123} KP_Period {83 124} Boot {83 125} KP_Period {83 126} Boot {83 127} KP_Period {84 0} Last_Console {84 1} Last_Console {84 2} Last_Console {84 3} Last_Console {84 4} Last_Console {84 5} Last_Console {84 6} Last_Console {84 7} Last_Console {84 8} Last_Console {84 9} Last_Console {84 10} Last_Console {84 11} Last_Console {84 12} Last_Console {84 13} Last_Console {84 14} Last_Console {84 15} Last_Console {84 16} Last_Console {84 17} Last_Console {84 18} Last_Console {84 19} Last_Console {84 20} Last_Console {84 21} Last_Console {84 22} Last_Console {84 23} Last_Console {84 24} Last_Console {84 25} Last_Console {84 26} Last_Console {84 27} Last_Console {84 28} Last_Console {84 29} Last_Console {84 30} Last_Console {84 31} Last_Console {84 32} Last_Console {84 33} Last_Console {84 34} Last_Console {84 35} Last_Console {84 36} Last_Console {84 37} Last_Console {84 38} Last_Console {84 39} Last_Console {84 40} Last_Console {84 41} Last_Console {84 42} Last_Console {84 43} Last_Console {84 44} Last_Console {84 45} Last_Console {84 46} Last_Console {84 47} Last_Console {84 48} Last_Console {84 49} Last_Console {84 50} Last_Console {84 51} Last_Console {84 52} Last_Console {84 53} Last_Console {84 54} Last_Console {84 55} Last_Console {84 56} Last_Console {84 57} Last_Console {84 58} Last_Console {84 59} Last_Console {84 60} Last_Console {84 61} Last_Console {84 62} Last_Console {84 63} Last_Console {84 64} Last_Console {84 65} Last_Console {84 66} Last_Console {84 67} Last_Console {84 68} Last_Console {84 69} Last_Console {84 70} Last_Console {84 71} Last_Console {84 72} Last_Console {84 73} Last_Console {84 74} Last_Console {84 75} Last_Console {84 76} Last_Console {84 77} Last_Console {84 78} Last_Console {84 79} Last_Console {84 80} Last_Console {84 81} Last_Console {84 82} Last_Console {84 83} Last_Console {84 84} Last_Console {84 85} Last_Console {84 86} Last_Console {84 87} Last_Console {84 88} Last_Console {84 89} Last_Console {84 90} Last_Console {84 91} Last_Console {84 92} Last_Console {84 93} Last_Console {84 94} Last_Console {84 95} Last_Console {84 96} Last_Console {84 97} Last_Console {84 98} Last_Console {84 99} Last_Console {84 100} Last_Console {84 101} Last_Console {84 102} Last_Console {84 103} Last_Console {84 104} Last_Console {84 105} Last_Console {84 106} Last_Console {84 107} Last_Console {84 108} Last_Console {84 109} Last_Console {84 110} Last_Console {84 111} Last_Console {84 112} Last_Console {84 113} Last_Console {84 114} Last_Console {84 115} Last_Console {84 116} Last_Console {84 117} Last_Console {84 118} Last_Console {84 119} Last_Console {84 120} Last_Console {84 121} Last_Console {84 122} Last_Console {84 123} Last_Console {84 124} Last_Console {84 125} Last_Console {84 126} Last_Console {84 127} Last_Console {86 0} less {86 1} greater {86 2} bar {86 3} brokenbar {86 4} Control_backslash {86 5} greater {86 6} Control_backslash {86 7} Control_backslash {86 8} Meta_less {86 9} Meta_greater {86 10} Meta_bar {86 11} Meta_bar {86 12} Meta_Control_backslash {86 13} Meta_greater {86 14} Meta_Control_backslash {86 15} Meta_Control_backslash {86 16} less {86 17} greater {86 18} bar {86 19} brokenbar {86 20} Control_backslash {86 21} greater {86 22} Control_backslash {86 23} Control_backslash {86 24} Meta_less {86 25} Meta_greater {86 26} Meta_bar {86 27} Meta_bar {86 28} Meta_Control_backslash {86 29} Meta_greater {86 30} Meta_Control_backslash {86 31} Meta_Control_backslash {86 32} less {86 33} greater {86 34} bar {86 35} brokenbar {86 36} Control_backslash {86 37} greater {86 38} Control_backslash {86 39} Control_backslash {86 40} Meta_less {86 41} Meta_greater {86 42} Meta_bar {86 43} Meta_bar {86 44} Meta_Control_backslash {86 45} Meta_greater {86 46} Meta_Control_backslash {86 47} Meta_Control_backslash {86 48} less {86 49} greater {86 50} bar {86 51} brokenbar {86 52} Control_backslash {86 53} greater {86 54} Control_backslash {86 55} Control_backslash {86 56} Meta_less {86 57} Meta_greater {86 58} Meta_bar {86 59} Meta_bar {86 60} Meta_Control_backslash {86 61} Meta_greater {86 62} Meta_Control_backslash {86 63} Meta_Control_backslash {86 64} less {86 65} greater {86 66} bar {86 67} brokenbar {86 68} Control_backslash {86 69} greater {86 70} Control_backslash {86 71} Control_backslash {86 72} Meta_less {86 73} Meta_greater {86 74} Meta_bar {86 75} Meta_bar {86 76} Meta_Control_backslash {86 77} Meta_greater {86 78} Meta_Control_backslash {86 79} Meta_Control_backslash {86 80} less {86 81} greater {86 82} bar {86 83} brokenbar {86 84} Control_backslash {86 85} greater {86 86} Control_backslash {86 87} Control_backslash {86 88} Meta_less {86 89} Meta_greater {86 90} Meta_bar {86 91} Meta_bar {86 92} Meta_Control_backslash {86 93} Meta_greater {86 94} Meta_Control_backslash {86 95} Meta_Control_backslash {86 96} less {86 97} greater {86 98} bar {86 99} brokenbar {86 100} Control_backslash {86 101} greater {86 102} Control_backslash {86 103} Control_backslash {86 104} Meta_less {86 105} Meta_greater {86 106} Meta_bar {86 107} Meta_bar {86 108} Meta_Control_backslash {86 109} Meta_greater {86 110} Meta_Control_backslash {86 111} Meta_Control_backslash {86 112} less {86 113} greater {86 114} bar {86 115} brokenbar {86 116} Control_backslash {86 117} greater {86 118} Control_backslash {86 119} Control_backslash {86 120} Meta_less {86 121} Meta_greater {86 122} Meta_bar {86 123} Meta_bar {86 124} Meta_Control_backslash {86 125} Meta_greater {86 126} Meta_Control_backslash {86 127} Meta_Control_backslash {87 0} F11 {87 1} F23 {87 2} Console_23 {87 3} Console_35 {87 4} F35 {87 5} F47 {87 6} Console_23 {87 7} Console_35 {87 8} Console_11 {87 9} Console_23 {87 10} F11 {87 11} F11 {87 12} Console_11 {87 13} Console_23 {87 14} F11 {87 15} F11 {87 16} F11 {87 17} F23 {87 18} Console_23 {87 19} Console_35 {87 20} F35 {87 21} F47 {87 22} Console_23 {87 23} Console_35 {87 24} Console_11 {87 25} Console_23 {87 26} F11 {87 27} F11 {87 28} Console_11 {87 29} Console_23 {87 30} F11 {87 31} F11 {87 32} F11 {87 33} F23 {87 34} Console_23 {87 35} Console_35 {87 36} F35 {87 37} F47 {87 38} Console_23 {87 39} Console_35 {87 40} Console_11 {87 41} Console_23 {87 42} F11 {87 43} F11 {87 44} Console_11 {87 45} Console_23 {87 46} F11 {87 47} F11 {87 48} F11 {87 49} F23 {87 50} Console_23 {87 51} Console_35 {87 52} F35 {87 53} F47 {87 54} Console_23 {87 55} Console_35 {87 56} Console_11 {87 57} Console_23 {87 58} F11 {87 59} F11 {87 60} Console_11 {87 61} Console_23 {87 62} F11 {87 63} F11 {87 64} F11 {87 65} F23 {87 66} Console_23 {87 67} Console_35 {87 68} F35 {87 69} F47 {87 70} Console_23 {87 71} Console_35 {87 72} Console_11 {87 73} Console_23 {87 74} F11 {87 75} F11 {87 76} Console_11 {87 77} Console_23 {87 78} F11 {87 79} F11 {87 80} F11 {87 81} F23 {87 82} Console_23 {87 83} Console_35 {87 84} F35 {87 85} F47 {87 86} Console_23 {87 87} Console_35 {87 88} Console_11 {87 89} Console_23 {87 90} F11 {87 91} F11 {87 92} Console_11 {87 93} Console_23 {87 94} F11 {87 95} F11 {87 96} F11 {87 97} F23 {87 98} Console_23 {87 99} Console_35 {87 100} F35 {87 101} F47 {87 102} Console_23 {87 103} Console_35 {87 104} Console_11 {87 105} Console_23 {87 106} F11 {87 107} F11 {87 108} Console_11 {87 109} Console_23 {87 110} F11 {87 111} F11 {87 112} F11 {87 113} F23 {87 114} Console_23 {87 115} Console_35 {87 116} F35 {87 117} F47 {87 118} Console_23 {87 119} Console_35 {87 120} Console_11 {87 121} Console_23 {87 122} F11 {87 123} F11 {87 124} Console_11 {87 125} Console_23 {87 126} F11 {87 127} F11 {88 0} F12 {88 1} F24 {88 2} Console_24 {88 3} Console_36 {88 4} F36 {88 5} F48 {88 6} Console_24 {88 7} Console_36 {88 8} Console_12 {88 9} Console_24 {88 10} F12 {88 11} F12 {88 12} Console_12 {88 13} Console_24 {88 14} F12 {88 15} F12 {88 16} F12 {88 17} F24 {88 18} Console_24 {88 19} Console_36 {88 20} F36 {88 21} F48 {88 22} Console_24 {88 23} Console_36 {88 24} Console_12 {88 25} Console_24 {88 26} F12 {88 27} F12 {88 28} Console_12 {88 29} Console_24 {88 30} F12 {88 31} F12 {88 32} F12 {88 33} F24 {88 34} Console_24 {88 35} Console_36 {88 36} F36 {88 37} F48 {88 38} Console_24 {88 39} Console_36 {88 40} Console_12 {88 41} Console_24 {88 42} F12 {88 43} F12 {88 44} Console_12 {88 45} Console_24 {88 46} F12 {88 47} F12 {88 48} F12 {88 49} F24 {88 50} Console_24 {88 51} Console_36 {88 52} F36 {88 53} F48 {88 54} Console_24 {88 55} Console_36 {88 56} Console_12 {88 57} Console_24 {88 58} F12 {88 59} F12 {88 60} Console_12 {88 61} Console_24 {88 62} F12 {88 63} F12 {88 64} F12 {88 65} F24 {88 66} Console_24 {88 67} Console_36 {88 68} F36 {88 69} F48 {88 70} Console_24 {88 71} Console_36 {88 72} Console_12 {88 73} Console_24 {88 74} F12 {88 75} F12 {88 76} Console_12 {88 77} Console_24 {88 78} F12 {88 79} F12 {88 80} F12 {88 81} F24 {88 82} Console_24 {88 83} Console_36 {88 84} F36 {88 85} F48 {88 86} Console_24 {88 87} Console_36 {88 88} Console_12 {88 89} Console_24 {88 90} F12 {88 91} F12 {88 92} Console_12 {88 93} Console_24 {88 94} F12 {88 95} F12 {88 96} F12 {88 97} F24 {88 98} Console_24 {88 99} Console_36 {88 100} F36 {88 101} F48 {88 102} Console_24 {88 103} Console_36 {88 104} Console_12 {88 105} Console_24 {88 106} F12 {88 107} F12 {88 108} Console_12 {88 109} Console_24 {88 110} F12 {88 111} F12 {88 112} F12 {88 113} F24 {88 114} Console_24 {88 115} Console_36 {88 116} F36 {88 117} F48 {88 118} Console_24 {88 119} Console_36 {88 120} Console_12 {88 121} Console_24 {88 122} F12 {88 123} F12 {88 124} Console_12 {88 125} Console_24 {88 126} F12 {88 127} F12 {96 0} KP_Enter {96 1} KP_Enter {96 2} Hex_F {96 3} KP_Enter {96 4} KP_Enter {96 5} KP_Enter {96 6} KP_Enter {96 7} KP_Enter {96 8} KP_Enter {96 9} Hex_F {96 10} KP_Enter {96 11} KP_Enter {96 12} KP_Enter {96 13} KP_Enter {96 14} KP_Enter {96 15} KP_Enter {96 16} KP_Enter {96 17} KP_Enter {96 18} Hex_F {96 19} KP_Enter {96 20} KP_Enter {96 21} KP_Enter {96 22} KP_Enter {96 23} KP_Enter {96 24} KP_Enter {96 25} Hex_F {96 26} KP_Enter {96 27} KP_Enter {96 28} KP_Enter {96 29} KP_Enter {96 30} KP_Enter {96 31} KP_Enter {96 32} KP_Enter {96 33} KP_Enter {96 34} Hex_F {96 35} KP_Enter {96 36} KP_Enter {96 37} KP_Enter {96 38} KP_Enter {96 39} KP_Enter {96 40} KP_Enter {96 41} Hex_F {96 42} KP_Enter {96 43} KP_Enter {96 44} KP_Enter {96 45} KP_Enter {96 46} KP_Enter {96 47} KP_Enter {96 48} KP_Enter {96 49} KP_Enter {96 50} Hex_F {96 51} KP_Enter {96 52} KP_Enter {96 53} KP_Enter {96 54} KP_Enter {96 55} KP_Enter {96 56} KP_Enter {96 57} Hex_F {96 58} KP_Enter {96 59} KP_Enter {96 60} KP_Enter {96 61} KP_Enter {96 62} KP_Enter {96 63} KP_Enter {96 64} KP_Enter {96 65} KP_Enter {96 66} Hex_F {96 67} KP_Enter {96 68} KP_Enter {96 69} KP_Enter {96 70} KP_Enter {96 71} KP_Enter {96 72} KP_Enter {96 73} Hex_F {96 74} KP_Enter {96 75} KP_Enter {96 76} KP_Enter {96 77} KP_Enter {96 78} KP_Enter {96 79} KP_Enter {96 80} KP_Enter {96 81} KP_Enter {96 82} Hex_F {96 83} KP_Enter {96 84} KP_Enter {96 85} KP_Enter {96 86} KP_Enter {96 87} KP_Enter {96 88} KP_Enter {96 89} Hex_F {96 90} KP_Enter {96 91} KP_Enter {96 92} KP_Enter {96 93} KP_Enter {96 94} KP_Enter {96 95} KP_Enter {96 96} KP_Enter {96 97} KP_Enter {96 98} Hex_F {96 99} KP_Enter {96 100} KP_Enter {96 101} KP_Enter {96 102} KP_Enter {96 103} KP_Enter {96 104} KP_Enter {96 105} Hex_F {96 106} KP_Enter {96 107} KP_Enter {96 108} KP_Enter {96 109} KP_Enter {96 110} KP_Enter {96 111} KP_Enter {96 112} KP_Enter {96 113} KP_Enter {96 114} Hex_F {96 115} KP_Enter {96 116} KP_Enter {96 117} KP_Enter {96 118} KP_Enter {96 119} KP_Enter {96 120} KP_Enter {96 121} Hex_F {96 122} KP_Enter {96 123} KP_Enter {96 124} KP_Enter {96 125} KP_Enter {96 126} KP_Enter {96 127} KP_Enter {97 0} Control {97 1} Control {97 2} Control {97 3} Control {97 4} Control {97 5} Control {97 6} Control {97 7} Control {97 8} Control {97 9} Control {97 10} Control {97 11} Control {97 12} Control {97 13} Control {97 14} Control {97 15} Control {97 16} Control {97 17} Control {97 18} Control {97 19} Control {97 20} Control {97 21} Control {97 22} Control {97 23} Control {97 24} Control {97 25} Control {97 26} Control {97 27} Control {97 28} Control {97 29} Control {97 30} Control {97 31} Control {97 32} Control {97 33} Control {97 34} Control {97 35} Control {97 36} Control {97 37} Control {97 38} Control {97 39} Control {97 40} Control {97 41} Control {97 42} Control {97 43} Control {97 44} Control {97 45} Control {97 46} Control {97 47} Control {97 48} Control {97 49} Control {97 50} Control {97 51} Control {97 52} Control {97 53} Control {97 54} Control {97 55} Control {97 56} Control {97 57} Control {97 58} Control {97 59} Control {97 60} Control {97 61} Control {97 62} Control {97 63} Control {97 64} Control {97 65} Control {97 66} Control {97 67} Control {97 68} Control {97 69} Control {97 70} Control {97 71} Control {97 72} Control {97 73} Control {97 74} Control {97 75} Control {97 76} Control {97 77} Control {97 78} Control {97 79} Control {97 80} Control {97 81} Control {97 82} Control {97 83} Control {97 84} Control {97 85} Control {97 86} Control {97 87} Control {97 88} Control {97 89} Control {97 90} Control {97 91} Control {97 92} Control {97 93} Control {97 94} Control {97 95} Control {97 96} Control {97 97} Control {97 98} Control {97 99} Control {97 100} Control {97 101} Control {97 102} Control {97 103} Control {97 104} Control {97 105} Control {97 106} Control {97 107} Control {97 108} Control {97 109} Control {97 110} Control {97 111} Control {97 112} Control {97 113} Control {97 114} Control {97 115} Control {97 116} Control {97 117} Control {97 118} Control {97 119} Control {97 120} Control {97 121} Control {97 122} Control {97 123} Control {97 124} Control {97 125} Control {97 126} Control {97 127} Control {98 0} KP_Divide {98 1} KP_Divide {98 2} Hex_B {98 3} KP_Divide {98 4} KP_Divide {98 5} KP_Divide {98 6} KP_Divide {98 7} KP_Divide {98 8} KP_Divide {98 9} Hex_B {98 10} KP_Divide {98 11} KP_Divide {98 12} KP_Divide {98 13} KP_Divide {98 14} KP_Divide {98 15} KP_Divide {98 16} KP_Divide {98 17} KP_Divide {98 18} Hex_B {98 19} KP_Divide {98 20} KP_Divide {98 21} KP_Divide {98 22} KP_Divide {98 23} KP_Divide {98 24} KP_Divide {98 25} Hex_B {98 26} KP_Divide {98 27} KP_Divide {98 28} KP_Divide {98 29} KP_Divide {98 30} KP_Divide {98 31} KP_Divide {98 32} KP_Divide {98 33} KP_Divide {98 34} Hex_B {98 35} KP_Divide {98 36} KP_Divide {98 37} KP_Divide {98 38} KP_Divide {98 39} KP_Divide {98 40} KP_Divide {98 41} Hex_B {98 42} KP_Divide {98 43} KP_Divide {98 44} KP_Divide {98 45} KP_Divide {98 46} KP_Divide {98 47} KP_Divide {98 48} KP_Divide {98 49} KP_Divide {98 50} Hex_B {98 51} KP_Divide {98 52} KP_Divide {98 53} KP_Divide {98 54} KP_Divide {98 55} KP_Divide {98 56} KP_Divide {98 57} Hex_B {98 58} KP_Divide {98 59} KP_Divide {98 60} KP_Divide {98 61} KP_Divide {98 62} KP_Divide {98 63} KP_Divide {98 64} KP_Divide {98 65} KP_Divide {98 66} Hex_B {98 67} KP_Divide {98 68} KP_Divide {98 69} KP_Divide {98 70} KP_Divide {98 71} KP_Divide {98 72} KP_Divide {98 73} Hex_B {98 74} KP_Divide {98 75} KP_Divide {98 76} KP_Divide {98 77} KP_Divide {98 78} KP_Divide {98 79} KP_Divide {98 80} KP_Divide {98 81} KP_Divide {98 82} Hex_B {98 83} KP_Divide {98 84} KP_Divide {98 85} KP_Divide {98 86} KP_Divide {98 87} KP_Divide {98 88} KP_Divide {98 89} Hex_B {98 90} KP_Divide {98 91} KP_Divide {98 92} KP_Divide {98 93} KP_Divide {98 94} KP_Divide {98 95} KP_Divide {98 96} KP_Divide {98 97} KP_Divide {98 98} Hex_B {98 99} KP_Divide {98 100} KP_Divide {98 101} KP_Divide {98 102} KP_Divide {98 103} KP_Divide {98 104} KP_Divide {98 105} Hex_B {98 106} KP_Divide {98 107} KP_Divide {98 108} KP_Divide {98 109} KP_Divide {98 110} KP_Divide {98 111} KP_Divide {98 112} KP_Divide {98 113} KP_Divide {98 114} Hex_B {98 115} KP_Divide {98 116} KP_Divide {98 117} KP_Divide {98 118} KP_Divide {98 119} KP_Divide {98 120} KP_Divide {98 121} Hex_B {98 122} KP_Divide {98 123} KP_Divide {98 124} KP_Divide {98 125} KP_Divide {98 126} KP_Divide {98 127} KP_Divide {99 0} Control_backslash {99 1} Control_backslash {99 2} Control_backslash {99 3} Control_backslash {99 4} Control_backslash {99 5} Control_backslash {99 6} Last_Console {99 7} Last_Console {99 8} Last_Console {99 9} Last_Console {99 10} Meta_Control_backslash {99 11} Meta_Control_backslash {99 12} Meta_Control_backslash {99 13} Meta_Control_backslash {99 14} Control_backslash {99 15} Control_backslash {99 16} Control_backslash {99 17} Control_backslash {99 18} Control_backslash {99 19} Control_backslash {99 20} Last_Console {99 21} Last_Console {99 22} Last_Console {99 23} Last_Console {99 24} Meta_Control_backslash {99 25} Meta_Control_backslash {99 26} Meta_Control_backslash {99 27} Meta_Control_backslash {99 28} Control_backslash {99 29} Control_backslash {99 30} Control_backslash {99 31} Control_backslash {99 32} Control_backslash {99 33} Control_backslash {99 34} Last_Console {99 35} Last_Console {99 36} Last_Console {99 37} Last_Console {99 38} Meta_Control_backslash {99 39} Meta_Control_backslash {99 40} Meta_Control_backslash {99 41} Meta_Control_backslash {99 42} Control_backslash {99 43} Control_backslash {99 44} Control_backslash {99 45} Control_backslash {99 46} Control_backslash {99 47} Control_backslash {99 48} Last_Console {99 49} Last_Console {99 50} Last_Console {99 51} Last_Console {99 52} Meta_Control_backslash {99 53} Meta_Control_backslash {99 54} Meta_Control_backslash {99 55} Meta_Control_backslash {99 56} Control_backslash {99 57} Control_backslash {99 58} Control_backslash {99 59} Control_backslash {99 60} Control_backslash {99 61} Control_backslash {99 62} Last_Console {99 63} Last_Console {99 64} Last_Console {99 65} Last_Console {99 66} Meta_Control_backslash {99 67} Meta_Control_backslash {99 68} Meta_Control_backslash {99 69} Meta_Control_backslash {99 70} Control_backslash {99 71} Control_backslash {99 72} Control_backslash {99 73} Control_backslash {99 74} Control_backslash {99 75} Control_backslash {99 76} Last_Console {99 77} Last_Console {99 78} Last_Console {99 79} Last_Console {99 80} Meta_Control_backslash {99 81} Meta_Control_backslash {99 82} Meta_Control_backslash {99 83} Meta_Control_backslash {99 84} Control_backslash {99 85} Control_backslash {99 86} Control_backslash {99 87} Control_backslash {99 88} Control_backslash {99 89} Control_backslash {99 90} Last_Console {99 91} Last_Console {99 92} Last_Console {99 93} Last_Console {99 94} Meta_Control_backslash {99 95} Meta_Control_backslash {99 96} Meta_Control_backslash {99 97} Meta_Control_backslash {99 98} Control_backslash {99 99} Control_backslash {99 100} Control_backslash {99 101} Control_backslash {99 102} Control_backslash {99 103} Control_backslash {99 104} Last_Console {99 105} Last_Console {99 106} Last_Console {99 107} Last_Console {99 108} Meta_Control_backslash {99 109} Meta_Control_backslash {99 110} Meta_Control_backslash {99 111} Meta_Control_backslash {100 0} Alt {100 1} Alt {100 2} Alt {100 3} Alt {100 4} Alt {100 5} Alt {100 6} Alt {100 7} Alt {100 8} Alt {100 9} Alt {100 10} Alt {100 11} Alt {100 12} Alt {100 13} Alt {100 14} Alt {100 15} Alt {100 16} Alt {100 17} Alt {100 18} Alt {100 19} Alt {100 20} Alt {100 21} Alt {100 22} Alt {100 23} Alt {100 24} Alt {100 25} Alt {100 26} Alt {100 27} Alt {100 28} Alt {100 29} Alt {100 30} Alt {100 31} Alt {100 32} Alt {100 33} Alt {100 34} Alt {100 35} Alt {100 36} Alt {100 37} Alt {100 38} Alt {100 39} Alt {100 40} Alt {100 41} Alt {100 42} Alt {100 43} Alt {100 44} Alt {100 45} Alt {100 46} Alt {100 47} Alt {100 48} Alt {100 49} Alt {100 50} Alt {100 51} Alt {100 52} Alt {100 53} Alt {100 54} Alt {100 55} Alt {100 56} Alt {100 57} Alt {100 58} Alt {100 59} Alt {100 60} Alt {100 61} Alt {100 62} Alt {100 63} Alt {100 64} Alt {100 65} Alt {100 66} Alt {100 67} Alt {100 68} Alt {100 69} Alt {100 70} Alt {100 71} Alt {100 72} Alt {100 73} Alt {100 74} Alt {100 75} Alt {100 76} Alt {100 77} Alt {100 78} Alt {100 79} Alt {100 80} Alt {100 81} Alt {100 82} Alt {100 83} Alt {100 84} Alt {100 85} Alt {100 86} Alt {100 87} Alt {100 88} Alt {100 89} Alt {100 90} Alt {100 91} Alt {100 92} Alt {100 93} Alt {100 94} Alt {100 95} Alt {100 96} Alt {100 97} Alt {100 98} Alt {100 99} Alt {100 100} Alt {100 101} Alt {100 102} Alt {100 103} Alt {100 104} Alt {100 105} Alt {100 106} Alt {100 107} Alt {100 108} Alt {100 109} Alt {100 110} Alt {100 111} Alt {100 112} Alt {100 113} Alt {100 114} Alt {100 115} Alt {100 116} Alt {100 117} Alt {100 118} Alt {100 119} Alt {100 120} Alt {100 121} Alt {100 122} Alt {100 123} Alt {100 124} Alt {100 125} Alt {100 126} Alt {100 127} Alt {101 0} Break {101 1} Break {101 2} Break {101 3} Break {101 4} Break {101 5} Break {101 6} Break {101 7} Break {101 8} Break {101 9} Break {101 10} Break {101 11} Break {101 12} Break {101 13} Break {101 14} Break {101 15} Break {101 16} Break {101 17} Break {101 18} Break {101 19} Break {101 20} Break {101 21} Break {101 22} Break {101 23} Break {101 24} Break {101 25} Break {101 26} Break {101 27} Break {101 28} Break {101 29} Break {101 30} Break {101 31} Break {101 32} Break {101 33} Break {101 34} Break {101 35} Break {101 36} Break {101 37} Break {101 38} Break {101 39} Break {101 40} Break {101 41} Break {101 42} Break {101 43} Break {101 44} Break {101 45} Break {101 46} Break {101 47} Break {101 48} Break {101 49} Break {101 50} Break {101 51} Break {101 52} Break {101 53} Break {101 54} Break {101 55} Break {101 56} Break {101 57} Break {101 58} Break {101 59} Break {101 60} Break {101 61} Break {101 62} Break {101 63} Break {101 64} Break {101 65} Break {101 66} Break {101 67} Break {101 68} Break {101 69} Break {101 70} Break {101 71} Break {101 72} Break {101 73} Break {101 74} Break {101 75} Break {101 76} Break {101 77} Break {101 78} Break {101 79} Break {101 80} Break {101 81} Break {101 82} Break {101 83} Break {101 84} Break {101 85} Break {101 86} Break {101 87} Break {101 88} Break {101 89} Break {101 90} Break {101 91} Break {101 92} Break {101 93} Break {101 94} Break {101 95} Break {101 96} Break {101 97} Break {101 98} Break {101 99} Break {101 100} Break {101 101} Break {101 102} Break {101 103} Break {101 104} Break {101 105} Break {101 106} Break {101 107} Break {101 108} Break {101 109} Break {101 110} Break {101 111} Break {101 112} Break {101 113} Break {101 114} Break {101 115} Break {101 116} Break {101 117} Break {101 118} Break {101 119} Break {101 120} Break {101 121} Break {101 122} Break {101 123} Break {101 124} Break {101 125} Break {101 126} Break {101 127} Break {102 0} Find {102 1} Find {102 2} Find {102 3} Find {102 4} Find {102 5} Find {102 6} Find {102 7} Find {102 8} Find {102 9} Find {102 10} Find {102 11} Find {102 12} Find {102 13} Find {102 14} Find {102 15} Find {102 16} Find {102 17} Find {102 18} Find {102 19} Find {102 20} Find {102 21} Find {102 22} Find {102 23} Find {102 24} Find {102 25} Find {102 26} Find {102 27} Find {102 28} Find {102 29} Find {102 30} Find {102 31} Find {102 32} Find {102 33} Find {102 34} Find {102 35} Find {102 36} Find {102 37} Find {102 38} Find {102 39} Find {102 40} Find {102 41} Find {102 42} Find {102 43} Find {102 44} Find {102 45} Find {102 46} Find {102 47} Find {102 48} Find {102 49} Find {102 50} Find {102 51} Find {102 52} Find {102 53} Find {102 54} Find {102 55} Find {102 56} Find {102 57} Find {102 58} Find {102 59} Find {102 60} Find {102 61} Find {102 62} Find {102 63} Find {102 64} Find {102 65} Find {102 66} Find {102 67} Find {102 68} Find {102 69} Find {102 70} Find {102 71} Find {102 72} Find {102 73} Find {102 74} Find {102 75} Find {102 76} Find {102 77} Find {102 78} Find {102 79} Find {102 80} Find {102 81} Find {102 82} Find {102 83} Find {102 84} Find {102 85} Find {102 86} Find {102 87} Find {102 88} Find {102 89} Find {102 90} Find {102 91} Find {102 92} Find {102 93} Find {102 94} Find {102 95} Find {102 96} Find {102 97} Find {102 98} Find {102 99} Find {102 100} Find {102 101} Find {102 102} Find {102 103} Find {102 104} Find {102 105} Find {102 106} Find {102 107} Find {102 108} Find {102 109} Find {102 110} Find {102 111} Find {102 112} Find {102 113} Find {102 114} Find {102 115} Find {102 116} Find {102 117} Find {102 118} Find {102 119} Find {102 120} Find {102 121} Find {102 122} Find {102 123} Find {102 124} Find {102 125} Find {102 126} Find {102 127} Find {103 0} Up {103 1} Up {103 2} Up {103 3} Up {103 4} Up {103 5} Up {103 6} Up {103 7} Up {103 8} KeyboardSignal {103 9} Up {103 10} Up {103 11} Up {103 12} Up {103 13} Up {103 14} Up {103 15} Up {103 16} Up {103 17} Up {103 18} Up {103 19} Up {103 20} Up {103 21} Up {103 22} Up {103 23} Up {103 24} KeyboardSignal {103 25} Up {103 26} Up {103 27} Up {103 28} Up {103 29} Up {103 30} Up {103 31} Up {103 32} Up {103 33} Up {103 34} Up {103 35} Up {103 36} Up {103 37} Up {103 38} Up {103 39} Up {103 40} KeyboardSignal {103 41} Up {103 42} Up {103 43} Up {103 44} Up {103 45} Up {103 46} Up {103 47} Up {103 48} Up {103 49} Up {103 50} Up {103 51} Up {103 52} Up {103 53} Up {103 54} Up {103 55} Up {103 56} KeyboardSignal {103 57} Up {103 58} Up {103 59} Up {103 60} Up {103 61} Up {103 62} Up {103 63} Up {103 64} Up {103 65} Up {103 66} Up {103 67} Up {103 68} Up {103 69} Up {103 70} Up {103 71} Up {103 72} KeyboardSignal {103 73} Up {103 74} Up {103 75} Up {103 76} Up {103 77} Up {103 78} Up {103 79} Up {103 80} Up {103 81} Up {103 82} Up {103 83} Up {103 84} Up {103 85} Up {103 86} Up {103 87} Up {103 88} KeyboardSignal {103 89} Up {103 90} Up {103 91} Up {103 92} Up {103 93} Up {103 94} Up {103 95} Up {103 96} Up {103 97} Up {103 98} Up {103 99} Up {103 100} Up {103 101} Up {103 102} Up {103 103} Up {103 104} KeyboardSignal {103 105} Up {103 106} Up {103 107} Up {103 108} Up {103 109} Up {103 110} Up {103 111} Up {103 112} Up {103 113} Up {103 114} Up {103 115} Up {103 116} Up {103 117} Up {103 118} Up {103 119} Up {103 120} KeyboardSignal {103 121} Up {103 122} Up {103 123} Up {103 124} Up {103 125} Up {103 126} Up {103 127} Up {104 0} Prior {104 1} Scroll_Backward {104 2} Prior {104 3} Prior {104 4} Prior {104 5} Prior {104 6} Prior {104 7} Prior {104 8} Prior {104 9} Prior {104 10} Prior {104 11} Prior {104 12} Prior {104 13} Prior {104 14} Prior {104 15} Prior {104 16} Prior {104 17} Scroll_Backward {104 18} Prior {104 19} Prior {104 20} Prior {104 21} Prior {104 22} Prior {104 23} Prior {104 24} Prior {104 25} Prior {104 26} Prior {104 27} Prior {104 28} Prior {104 29} Prior {104 30} Prior {104 31} Prior {104 32} Prior {104 33} Scroll_Backward {104 34} Prior {104 35} Prior {104 36} Prior {104 37} Prior {104 38} Prior {104 39} Prior {104 40} Prior {104 41} Prior {104 42} Prior {104 43} Prior {104 44} Prior {104 45} Prior {104 46} Prior {104 47} Prior {104 48} Prior {104 49} Scroll_Backward {104 50} Prior {104 51} Prior {104 52} Prior {104 53} Prior {104 54} Prior {104 55} Prior {104 56} Prior {104 57} Prior {104 58} Prior {104 59} Prior {104 60} Prior {104 61} Prior {104 62} Prior {104 63} Prior {104 64} Prior {104 65} Scroll_Backward {104 66} Prior {104 67} Prior {104 68} Prior {104 69} Prior {104 70} Prior {104 71} Prior {104 72} Prior {104 73} Prior {104 74} Prior {104 75} Prior {104 76} Prior {104 77} Prior {104 78} Prior {104 79} Prior {104 80} Prior {104 81} Scroll_Backward {104 82} Prior {104 83} Prior {104 84} Prior {104 85} Prior {104 86} Prior {104 87} Prior {104 88} Prior {104 89} Prior {104 90} Prior {104 91} Prior {104 92} Prior {104 93} Prior {104 94} Prior {104 95} Prior {104 96} Prior {104 97} Scroll_Backward {104 98} Prior {104 99} Prior {104 100} Prior {104 101} Prior {104 102} Prior {104 103} Prior {104 104} Prior {104 105} Prior {104 106} Prior {104 107} Prior {104 108} Prior {104 109} Prior {104 110} Prior {104 111} Prior {104 112} Prior {104 113} Scroll_Backward {104 114} Prior {104 115} Prior {104 116} Prior {104 117} Prior {104 118} Prior {104 119} Prior {104 120} Prior {104 121} Prior {104 122} Prior {104 123} Prior {104 124} Prior {104 125} Prior {104 126} Prior {104 127} Prior {105 0} Left {105 1} Left {105 2} Left {105 3} Left {105 4} Left {105 5} Left {105 6} Left {105 7} Left {105 8} Decr_Console {105 9} Left {105 10} Left {105 11} Left {105 12} Left {105 13} Left {105 14} Left {105 15} Left {105 16} Left {105 17} Left {105 18} Left {105 19} Left {105 20} Left {105 21} Left {105 22} Left {105 23} Left {105 24} Decr_Console {105 25} Left {105 26} Left {105 27} Left {105 28} Left {105 29} Left {105 30} Left {105 31} Left {105 32} Left {105 33} Left {105 34} Left {105 35} Left {105 36} Left {105 37} Left {105 38} Left {105 39} Left {105 40} Decr_Console {105 41} Left {105 42} Left {105 43} Left {105 44} Left {105 45} Left {105 46} Left {105 47} Left {105 48} Left {105 49} Left {105 50} Left {105 51} Left {105 52} Left {105 53} Left {105 54} Left {105 55} Left {105 56} Decr_Console {105 57} Left {105 58} Left {105 59} Left {105 60} Left {105 61} Left {105 62} Left {105 63} Left {105 64} Left {105 65} Left {105 66} Left {105 67} Left {105 68} Left {105 69} Left {105 70} Left {105 71} Left {105 72} Decr_Console {105 73} Left {105 74} Left {105 75} Left {105 76} Left {105 77} Left {105 78} Left {105 79} Left {105 80} Left {105 81} Left {105 82} Left {105 83} Left {105 84} Left {105 85} Left {105 86} Left {105 87} Left {105 88} Decr_Console {105 89} Left {105 90} Left {105 91} Left {105 92} Left {105 93} Left {105 94} Left {105 95} Left {105 96} Left {105 97} Left {105 98} Left {105 99} Left {105 100} Left {105 101} Left {105 102} Left {105 103} Left {105 104} Decr_Console {105 105} Left {105 106} Left {105 107} Left {105 108} Left {105 109} Left {105 110} Left {105 111} Left {105 112} Left {105 113} Left {105 114} Left {105 115} Left {105 116} Left {105 117} Left {105 118} Left {105 119} Left {105 120} Decr_Console {105 121} Left {105 122} Left {105 123} Left {105 124} Left {105 125} Left {105 126} Left {105 127} Left {106 0} Right {106 1} Right {106 2} Right {106 3} Right {106 4} Right {106 5} Right {106 6} Right {106 7} Right {106 8} Incr_Console {106 9} Right {106 10} Right {106 11} Right {106 12} Right {106 13} Right {106 14} Right {106 15} Right {106 16} Right {106 17} Right {106 18} Right {106 19} Right {106 20} Right {106 21} Right {106 22} Right {106 23} Right {106 24} Incr_Console {106 25} Right {106 26} Right {106 27} Right {106 28} Right {106 29} Right {106 30} Right {106 31} Right {106 32} Right {106 33} Right {106 34} Right {106 35} Right {106 36} Right {106 37} Right {106 38} Right {106 39} Right {106 40} Incr_Console {106 41} Right {106 42} Right {106 43} Right {106 44} Right {106 45} Right {106 46} Right {106 47} Right {106 48} Right {106 49} Right {106 50} Right {106 51} Right {106 52} Right {106 53} Right {106 54} Right {106 55} Right {106 56} Incr_Console {106 57} Right {106 58} Right {106 59} Right {106 60} Right {106 61} Right {106 62} Right {106 63} Right {106 64} Right {106 65} Right {106 66} Right {106 67} Right {106 68} Right {106 69} Right {106 70} Right {106 71} Right {106 72} Incr_Console {106 73} Right {106 74} Right {106 75} Right {106 76} Right {106 77} Right {106 78} Right {106 79} Right {106 80} Right {106 81} Right {106 82} Right {106 83} Right {106 84} Right {106 85} Right {106 86} Right {106 87} Right {106 88} Incr_Console {106 89} Right {106 90} Right {106 91} Right {106 92} Right {106 93} Right {106 94} Right {106 95} Right {106 96} Right {106 97} Right {106 98} Right {106 99} Right {106 100} Right {106 101} Right {106 102} Right {106 103} Right {106 104} Incr_Console {106 105} Right {106 106} Right {106 107} Right {106 108} Right {106 109} Right {106 110} Right {106 111} Right {106 112} Right {106 113} Right {106 114} Right {106 115} Right {106 116} Right {106 117} Right {106 118} Right {106 119} Right {106 120} Incr_Console {106 121} Right {106 122} Right {106 123} Right {106 124} Right {106 125} Right {106 126} Right {106 127} Right {107 0} Select {107 1} Select {107 2} Select {107 3} Select {107 4} Select {107 5} Select {107 6} Select {107 7} Select {107 8} Select {107 9} Select {107 10} Select {107 11} Select {107 12} Select {107 13} Select {107 14} Select {107 15} Select {107 16} Select {107 17} Select {107 18} Select {107 19} Select {107 20} Select {107 21} Select {107 22} Select {107 23} Select {107 24} Select {107 25} Select {107 26} Select {107 27} Select {107 28} Select {107 29} Select {107 30} Select {107 31} Select {107 32} Select {107 33} Select {107 34} Select {107 35} Select {107 36} Select {107 37} Select {107 38} Select {107 39} Select {107 40} Select {107 41} Select {107 42} Select {107 43} Select {107 44} Select {107 45} Select {107 46} Select {107 47} Select {107 48} Select {107 49} Select {107 50} Select {107 51} Select {107 52} Select {107 53} Select {107 54} Select {107 55} Select {107 56} Select {107 57} Select {107 58} Select {107 59} Select {107 60} Select {107 61} Select {107 62} Select {107 63} Select {107 64} Select {107 65} Select {107 66} Select {107 67} Select {107 68} Select {107 69} Select {107 70} Select {107 71} Select {107 72} Select {107 73} Select {107 74} Select {107 75} Select {107 76} Select {107 77} Select {107 78} Select {107 79} Select {107 80} Select {107 81} Select {107 82} Select {107 83} Select {107 84} Select {107 85} Select {107 86} Select {107 87} Select {107 88} Select {107 89} Select {107 90} Select {107 91} Select {107 92} Select {107 93} Select {107 94} Select {107 95} Select {107 96} Select {107 97} Select {107 98} Select {107 99} Select {107 100} Select {107 101} Select {107 102} Select {107 103} Select {107 104} Select {107 105} Select {107 106} Select {107 107} Select {107 108} Select {107 109} Select {107 110} Select {107 111} Select {107 112} Select {107 113} Select {107 114} Select {107 115} Select {107 116} Select {107 117} Select {107 118} Select {107 119} Select {107 120} Select {107 121} Select {107 122} Select {107 123} Select {107 124} Select {107 125} Select {107 126} Select {107 127} Select {108 0} Down {108 1} Down {108 2} Down {108 3} Down {108 4} Down {108 5} Down {108 6} Down {108 7} Down {108 8} Down {108 9} Down {108 10} Down {108 11} Down {108 12} Down {108 13} Down {108 14} Down {108 15} Down {108 16} Down {108 17} Down {108 18} Down {108 19} Down {108 20} Down {108 21} Down {108 22} Down {108 23} Down {108 24} Down {108 25} Down {108 26} Down {108 27} Down {108 28} Down {108 29} Down {108 30} Down {108 31} Down {108 32} Down {108 33} Down {108 34} Down {108 35} Down {108 36} Down {108 37} Down {108 38} Down {108 39} Down {108 40} Down {108 41} Down {108 42} Down {108 43} Down {108 44} Down {108 45} Down {108 46} Down {108 47} Down {108 48} Down {108 49} Down {108 50} Down {108 51} Down {108 52} Down {108 53} Down {108 54} Down {108 55} Down {108 56} Down {108 57} Down {108 58} Down {108 59} Down {108 60} Down {108 61} Down {108 62} Down {108 63} Down {108 64} Down {108 65} Down {108 66} Down {108 67} Down {108 68} Down {108 69} Down {108 70} Down {108 71} Down {108 72} Down {108 73} Down {108 74} Down {108 75} Down {108 76} Down {108 77} Down {108 78} Down {108 79} Down {108 80} Down {108 81} Down {108 82} Down {108 83} Down {108 84} Down {108 85} Down {108 86} Down {108 87} Down {108 88} Down {108 89} Down {108 90} Down {108 91} Down {108 92} Down {108 93} Down {108 94} Down {108 95} Down {108 96} Down {108 97} Down {108 98} Down {108 99} Down {108 100} Down {108 101} Down {108 102} Down {108 103} Down {108 104} Down {108 105} Down {108 106} Down {108 107} Down {108 108} Down {108 109} Down {108 110} Down {108 111} Down {108 112} Down {108 113} Down {108 114} Down {108 115} Down {108 116} Down {108 117} Down {108 118} Down {108 119} Down {108 120} Down {108 121} Down {108 122} Down {108 123} Down {108 124} Down {108 125} Down {108 126} Down {108 127} Down {109 0} Next {109 1} Scroll_Forward {109 2} Next {109 3} Next {109 4} Next {109 5} Next {109 6} Next {109 7} Next {109 8} Next {109 9} Next {109 10} Next {109 11} Next {109 12} Next {109 13} Next {109 14} Next {109 15} Next {109 16} Next {109 17} Scroll_Forward {109 18} Next {109 19} Next {109 20} Next {109 21} Next {109 22} Next {109 23} Next {109 24} Next {109 25} Next {109 26} Next {109 27} Next {109 28} Next {109 29} Next {109 30} Next {109 31} Next {109 32} Next {109 33} Scroll_Forward {109 34} Next {109 35} Next {109 36} Next {109 37} Next {109 38} Next {109 39} Next {109 40} Next {109 41} Next {109 42} Next {109 43} Next {109 44} Next {109 45} Next {109 46} Next {109 47} Next {109 48} Next {109 49} Scroll_Forward {109 50} Next {109 51} Next {109 52} Next {109 53} Next {109 54} Next {109 55} Next {109 56} Next {109 57} Next {109 58} Next {109 59} Next {109 60} Next {109 61} Next {109 62} Next {109 63} Next {109 64} Next {109 65} Scroll_Forward {109 66} Next {109 67} Next {109 68} Next {109 69} Next {109 70} Next {109 71} Next {109 72} Next {109 73} Next {109 74} Next {109 75} Next {109 76} Next {109 77} Next {109 78} Next {109 79} Next {109 80} Next {109 81} Scroll_Forward {109 82} Next {109 83} Next {109 84} Next {109 85} Next {109 86} Next {109 87} Next {109 88} Next {109 89} Next {109 90} Next {109 91} Next {109 92} Next {109 93} Next {109 94} Next {109 95} Next {109 96} Next {109 97} Scroll_Forward {109 98} Next {109 99} Next {109 100} Next {109 101} Next {109 102} Next {109 103} Next {109 104} Next {109 105} Next {109 106} Next {109 107} Next {109 108} Next {109 109} Next {109 110} Next {109 111} Next {109 112} Next {109 113} Scroll_Forward {109 114} Next {109 115} Next {109 116} Next {109 117} Next {109 118} Next {109 119} Next {109 120} Next {109 121} Next {109 122} Next {109 123} Next {109 124} Next {109 125} Next {109 126} Next {109 127} Next {110 0} Insert {110 1} Insert {110 2} Insert {110 3} Insert {110 4} Insert {110 5} Insert {110 6} Insert {110 7} Insert {110 8} Insert {110 9} Insert {110 10} Insert {110 11} Insert {110 12} Insert {110 13} Insert {110 14} Insert {110 15} Insert {110 16} Insert {110 17} Insert {110 18} Insert {110 19} Insert {110 20} Insert {110 21} Insert {110 22} Insert {110 23} Insert {110 24} Insert {110 25} Insert {110 26} Insert {110 27} Insert {110 28} Insert {110 29} Insert {110 30} Insert {110 31} Insert {110 32} Insert {110 33} Insert {110 34} Insert {110 35} Insert {110 36} Insert {110 37} Insert {110 38} Insert {110 39} Insert {110 40} Insert {110 41} Insert {110 42} Insert {110 43} Insert {110 44} Insert {110 45} Insert {110 46} Insert {110 47} Insert {110 48} Insert {110 49} Insert {110 50} Insert {110 51} Insert {110 52} Insert {110 53} Insert {110 54} Insert {110 55} Insert {110 56} Insert {110 57} Insert {110 58} Insert {110 59} Insert {110 60} Insert {110 61} Insert {110 62} Insert {110 63} Insert {110 64} Insert {110 65} Insert {110 66} Insert {110 67} Insert {110 68} Insert {110 69} Insert {110 70} Insert {110 71} Insert {110 72} Insert {110 73} Insert {110 74} Insert {110 75} Insert {110 76} Insert {110 77} Insert {110 78} Insert {110 79} Insert {110 80} Insert {110 81} Insert {110 82} Insert {110 83} Insert {110 84} Insert {110 85} Insert {110 86} Insert {110 87} Insert {110 88} Insert {110 89} Insert {110 90} Insert {110 91} Insert {110 92} Insert {110 93} Insert {110 94} Insert {110 95} Insert {110 96} Insert {110 97} Insert {110 98} Insert {110 99} Insert {110 100} Insert {110 101} Insert {110 102} Insert {110 103} Insert {110 104} Insert {110 105} Insert {110 106} Insert {110 107} Insert {110 108} Insert {110 109} Insert {110 110} Insert {110 111} Insert {110 112} Insert {110 113} Insert {110 114} Insert {110 115} Insert {110 116} Insert {110 117} Insert {110 118} Insert {110 119} Insert {110 120} Insert {110 121} Insert {110 122} Insert {110 123} Insert {110 124} Insert {110 125} Insert {110 126} Insert {110 127} Insert {111 0} Remove {111 1} Remove {111 2} Remove {111 3} Remove {111 4} Remove {111 5} Remove {111 6} Boot {111 7} Remove {111 8} Remove {111 9} Remove {111 10} Remove {111 11} Remove {111 12} Boot {111 13} Remove {111 14} Boot {111 15} Remove {111 16} Remove {111 17} Remove {111 18} Remove {111 19} Remove {111 20} Remove {111 21} Remove {111 22} Boot {111 23} Remove {111 24} Remove {111 25} Remove {111 26} Remove {111 27} Remove {111 28} Boot {111 29} Remove {111 30} Boot {111 31} Remove {111 32} Remove {111 33} Remove {111 34} Remove {111 35} Remove {111 36} Remove {111 37} Remove {111 38} Boot {111 39} Remove {111 40} Remove {111 41} Remove {111 42} Remove {111 43} Remove {111 44} Boot {111 45} Remove {111 46} Boot {111 47} Remove {111 48} Remove {111 49} Remove {111 50} Remove {111 51} Remove {111 52} Remove {111 53} Remove {111 54} Boot {111 55} Remove {111 56} Remove {111 57} Remove {111 58} Remove {111 59} Remove {111 60} Boot {111 61} Remove {111 62} Boot {111 63} Remove {111 64} Remove {111 65} Remove {111 66} Remove {111 67} Remove {111 68} Remove {111 69} Remove {111 70} Boot {111 71} Remove {111 72} Remove {111 73} Remove {111 74} Remove {111 75} Remove {111 76} Boot {111 77} Remove {111 78} Boot {111 79} Remove {111 80} Remove {111 81} Remove {111 82} Remove {111 83} Remove {111 84} Remove {111 85} Remove {111 86} Boot {111 87} Remove {111 88} Remove {111 89} Remove {111 90} Remove {111 91} Remove {111 92} Boot {111 93} Remove {111 94} Boot {111 95} Remove {111 96} Remove {111 97} Remove {111 98} Remove {111 99} Remove {111 100} Remove {111 101} Remove {111 102} Boot {111 103} Remove {111 104} Remove {111 105} Remove {111 106} Remove {111 107} Remove {111 108} Boot {111 109} Remove {111 110} Boot {111 111} Remove {111 112} Remove {111 113} Remove {111 114} Remove {111 115} Remove {111 116} Remove {111 117} Remove {111 118} Boot {111 119} Remove {111 120} Remove {111 121} Remove {111 122} Remove {111 123} Remove {111 124} Boot {111 125} Remove {111 126} Boot {111 127} Remove {112 0} Macro {112 1} Macro {112 2} Macro {112 3} Macro {112 4} Macro {112 5} Macro {112 6} Macro {113 0} F13 {113 1} F13 {113 2} F13 {113 3} F13 {113 4} F13 {113 5} F13 {113 6} F13 {114 0} F14 {114 1} F14 {114 2} F14 {114 3} F14 {114 4} F14 {114 5} F14 {114 6} F14 {115 0} Help {115 1} Help {115 2} Help {115 3} Help {115 4} Help {115 5} Help {115 6} Help {116 0} Do {116 1} Do {116 2} Do {116 3} Do {116 4} Do {116 5} Do {116 6} Do {117 0} F17 {117 1} F17 {117 2} F17 {117 3} F17 {117 4} F17 {117 5} F17 {117 6} F17 {118 0} KP_MinPlus {118 1} KP_MinPlus {118 2} KP_MinPlus {118 3} KP_MinPlus {118 4} KP_MinPlus {118 5} KP_MinPlus {118 6} KP_MinPlus {119 0} Pause {119 1} Pause {119 2} Pause {119 3} Pause {119 4} Break {119 5} Break {119 6} Break {119 7} Break {119 8} Pause {119 9} Pause {119 10} Pause {119 11} Pause {119 12} Break {119 13} Break {119 14} Break {119 15} Break {119 16} Pause {119 17} Pause {119 18} Pause {119 19} Pause {119 20} Break {119 21} Break {119 22} Break {119 23} Break {119 24} Pause {119 25} Pause {119 26} Pause {119 27} Pause {119 28} Break {119 29} Break {119 30} Break {119 31} Break {119 32} Pause {119 33} Pause {119 34} Pause {119 35} Pause {119 36} Break {119 37} Break {119 38} Break {119 39} Break {119 40} Pause {119 41} Pause {119 42} Pause {119 43} Pause {119 44} Break {119 45} Break {119 46} Break {119 47} Break {119 48} Pause {119 49} Pause {119 50} Pause {119 51} Pause {119 52} Break {119 53} Break {119 54} Break {119 55} Break {119 56} Pause {119 57} Pause {119 58} Pause {119 59} Pause {119 60} Break {119 61} Break {119 62} Break {119 63} Break {119 64} Pause {119 65} Pause {119 66} Pause {119 67} Pause {119 68} Break {119 69} Break {119 70} Break {119 71} Break {119 72} Pause {119 73} Pause {119 74} Pause {119 75} Pause {119 76} Break {119 77} Break {119 78} Break {119 79} Break {119 80} Pause {119 81} Pause {119 82} Pause {119 83} Pause {119 84} Break {119 85} Break {119 86} Break {119 87} Break {119 88} Pause {119 89} Pause {119 90} Pause {119 91} Pause {119 92} Break {119 93} Break {119 94} Break {119 95} Break {119 96} Pause {119 97} Pause {119 98} Pause {119 99} Pause {119 100} Break {119 101} Break {119 102} Break {119 103} Break {119 104} Pause {119 105} Pause {119 106} Pause {119 107} Pause {119 108} Break {119 109} Break {119 110} Break {119 111} Break {119 112} Pause {119 113} Pause {119 114} Pause {119 115} Pause {119 116} Break {119 117} Break {119 118} Break {119 119} Break {119 120} Pause {119 121} Pause {119 122} Pause {119 123} Pause {119 124} Break {119 125} Break {119 126} Break {119 127} Break {121 0} KP_Period {121 1} KP_Period {121 2} KP_Period {121 3} KP_Period {121 4} KP_Period {121 5} KP_Period {121 6} KP_Period {121 7} KP_Period {121 8} KP_Period {121 9} KP_Period {121 10} KP_Period {121 11} KP_Period {121 12} KP_Period {121 13} KP_Period {121 14} KP_Period {121 15} KP_Period {121 16} KP_Period {121 17} KP_Period {121 18} KP_Period {121 19} KP_Period {121 20} KP_Period {121 21} KP_Period {121 22} KP_Period {121 23} KP_Period {121 24} KP_Period {121 25} KP_Period {121 26} KP_Period {121 27} KP_Period {121 28} KP_Period {121 29} KP_Period {121 30} KP_Period {121 31} KP_Period {121 32} KP_Period {121 33} KP_Period {121 34} KP_Period {121 35} KP_Period {121 36} KP_Period {121 37} KP_Period {121 38} KP_Period {121 39} KP_Period {121 40} KP_Period {121 41} KP_Period {121 42} KP_Period {121 43} KP_Period {121 44} KP_Period {121 45} KP_Period {121 46} KP_Period {121 47} KP_Period {121 48} KP_Period {121 49} KP_Period {121 50} KP_Period {121 51} KP_Period {121 52} KP_Period {121 53} KP_Period {121 54} KP_Period {121 55} KP_Period {121 56} KP_Period {121 57} KP_Period {121 58} KP_Period {121 59} KP_Period {121 60} KP_Period {121 61} KP_Period {121 62} KP_Period {121 63} KP_Period {121 64} KP_Period {121 65} KP_Period {121 66} KP_Period {121 67} KP_Period {121 68} KP_Period {121 69} KP_Period {121 70} KP_Period {121 71} KP_Period {121 72} KP_Period {121 73} KP_Period {121 74} KP_Period {121 75} KP_Period {121 76} KP_Period {121 77} KP_Period {121 78} KP_Period {121 79} KP_Period {121 80} KP_Period {121 81} KP_Period {121 82} KP_Period {121 83} KP_Period {121 84} KP_Period {121 85} KP_Period {121 86} KP_Period {121 87} KP_Period {121 88} KP_Period {121 89} KP_Period {121 90} KP_Period {121 91} KP_Period {121 92} KP_Period {121 93} KP_Period {121 94} KP_Period {121 95} KP_Period {121 96} KP_Period {121 97} KP_Period {121 98} KP_Period {121 99} KP_Period {121 100} KP_Period {121 101} KP_Period {121 102} KP_Period {121 103} KP_Period {121 104} KP_Period {121 105} KP_Period {121 106} KP_Period {121 107} KP_Period {121 108} KP_Period {121 109} KP_Period {121 110} KP_Period {121 111} KP_Period {121 112} KP_Period {121 113} KP_Period {121 114} KP_Period {121 115} KP_Period {121 116} KP_Period {121 117} KP_Period {121 118} KP_Period {121 119} KP_Period {121 120} KP_Period {121 121} KP_Period {121 122} KP_Period {121 123} KP_Period {121 124} KP_Period {121 125} KP_Period {121 126} KP_Period {121 127} KP_Period {125 0} Alt {125 1} Alt {125 2} Alt {125 3} Alt {125 4} Alt {125 5} Alt {125 6} Alt {125 7} Alt {125 8} Alt {125 9} Alt {125 10} Alt {125 11} Alt {125 12} Alt {125 13} Alt {125 14} Alt {125 15} Alt {125 16} Alt {125 17} Alt {125 18} Alt {125 19} Alt {125 20} Alt {125 21} Alt {125 22} Alt {125 23} Alt {125 24} Alt {125 25} Alt {125 26} Alt {125 27} Alt {125 28} Alt {125 29} Alt {125 30} Alt {125 31} Alt {125 32} Alt {125 33} Alt {125 34} Alt {125 35} Alt {125 36} Alt {125 37} Alt {125 38} Alt {125 39} Alt {125 40} Alt {125 41} Alt {125 42} Alt {125 43} Alt {125 44} Alt {125 45} Alt {125 46} Alt {125 47} Alt {125 48} Alt {125 49} Alt {125 50} Alt {125 51} Alt {125 52} Alt {125 53} Alt {125 54} Alt {125 55} Alt {125 56} Alt {125 57} Alt {125 58} Alt {125 59} Alt {125 60} Alt {125 61} Alt {125 62} Alt {125 63} Alt {125 64} Alt {125 65} Alt {125 66} Alt {125 67} Alt {125 68} Alt {125 69} Alt {125 70} Alt {125 71} Alt {125 72} Alt {125 73} Alt {125 74} Alt {125 75} Alt {125 76} Alt {125 77} Alt {125 78} Alt {125 79} Alt {125 80} Alt {125 81} Alt {125 82} Alt {125 83} Alt {125 84} Alt {125 85} Alt {125 86} Alt {125 87} Alt {125 88} Alt {125 89} Alt {125 90} Alt {125 91} Alt {125 92} Alt {125 93} Alt {125 94} Alt {125 95} Alt {125 96} Alt {125 97} Alt {125 98} Alt {125 99} Alt {125 100} Alt {125 101} Alt {125 102} Alt {125 103} Alt {125 104} Alt {125 105} Alt {125 106} Alt {125 107} Alt {125 108} Alt {125 109} Alt {125 110} Alt {125 111} Alt {125 112} Alt {125 113} Alt {125 114} Alt {125 115} Alt {125 116} Alt {125 117} Alt {125 118} Alt {125 119} Alt {125 120} Alt {125 121} Alt {125 122} Alt {125 123} Alt {125 124} Alt {125 125} Alt {125 126} Alt {125 127} Alt {126 0} Alt {126 1} Alt {126 2} Alt {126 3} Alt {126 4} Alt {126 5} Alt {126 6} Alt {126 7} Alt {126 8} Alt {126 9} Alt {126 10} Alt {126 11} Alt {126 12} Alt {126 13} Alt {126 14} Alt {126 15} Alt {126 16} Alt {126 17} Alt {126 18} Alt {126 19} Alt {126 20} Alt {126 21} Alt {126 22} Alt {126 23} Alt {126 24} Alt {126 25} Alt {126 26} Alt {126 27} Alt {126 28} Alt {126 29} Alt {126 30} Alt {126 31} Alt {126 32} Alt {126 33} Alt {126 34} Alt {126 35} Alt {126 36} Alt {126 37} Alt {126 38} Alt {126 39} Alt {126 40} Alt {126 41} Alt {126 42} Alt {126 43} Alt {126 44} Alt {126 45} Alt {126 46} Alt {126 47} Alt {126 48} Alt {126 49} Alt {126 50} Alt {126 51} Alt {126 52} Alt {126 53} Alt {126 54} Alt {126 55} Alt {126 56} Alt {126 57} Alt {126 58} Alt {126 59} Alt {126 60} Alt {126 61} Alt {126 62} Alt {126 63} Alt {126 64} Alt {126 65} Alt {126 66} Alt {126 67} Alt {126 68} Alt {126 69} Alt {126 70} Alt {126 71} Alt {126 72} Alt {126 73} Alt {126 74} Alt {126 75} Alt {126 76} Alt {126 77} Alt {126 78} Alt {126 79} Alt {126 80} Alt {126 81} Alt {126 82} Alt {126 83} Alt {126 84} Alt {126 85} Alt {126 86} Alt {126 87} Alt {126 88} Alt {126 89} Alt {126 90} Alt {126 91} Alt {126 92} Alt {126 93} Alt {126 94} Alt {126 95} Alt {126 96} Alt {126 97} Alt {126 98} Alt {126 99} Alt {126 100} Alt {126 101} Alt {126 102} Alt {126 103} Alt {126 104} Alt {126 105} Alt {126 106} Alt {126 107} Alt {126 108} Alt {126 109} Alt {126 110} Alt {126 111} Alt {126 112} Alt {126 113} Alt {126 114} Alt {126 115} Alt {126 116} Alt {126 117} Alt {126 118} Alt {126 119} Alt {126 120} Alt {126 121} Alt {126 122} Alt {126 123} Alt {126 124} Alt {126 125} Alt {126 126} Alt {126 127} Alt} {{2 0} 1 {2 1} ! {2 2} 1 {2 3} ! {2 4} 1 {2 5} ! {2 6} 1 {2 7} ! {2 8} 1 {2 9} ! {2 10} 1 {2 11} ! {2 12} 1 {2 13} ! {2 14} 1 {2 15} ! {2 16} 1 {2 17} ! {2 18} 1 {2 19} ! {2 20} 1 {2 21} ! {2 22} 1 {2 23} ! {2 24} 1 {2 25} ! {2 26} 1 {2 27} ! {2 28} 1 {2 29} ! {2 30} 1 {2 31} ! {2 32} 1 {2 33} ! {2 34} 1 {2 35} ! {2 36} 1 {2 37} ! {2 38} 1 {2 39} ! {2 40} 1 {2 41} ! {2 42} 1 {2 43} ! {2 44} 1 {2 45} ! {2 46} 1 {2 47} ! {2 48} 1 {2 49} ! {2 50} 1 {2 51} ! {2 52} 1 {2 53} ! {2 54} 1 {2 55} ! {2 56} 1 {2 57} ! {2 58} 1 {2 59} ! {2 60} 1 {2 61} ! {2 62} 1 {2 63} ! {3 0} 2 {3 1} @ {3 2} 2 {3 3} @ {3 4} 2 {3 5} @ {3 6} 2 {3 7} @ {3 8} 2 {3 9} @ {3 10} 2 {3 11} @ {3 12} 2 {3 13} @ {3 14} 2 {3 15} @ {3 16} 2 {3 17} @ {3 18} 2 {3 19} @ {3 20} 2 {3 21} @ {3 22} 2 {3 23} @ {3 24} 2 {3 25} @ {3 26} 2 {3 27} @ {3 28} 2 {3 29} @ {3 30} 2 {3 31} @ {4 0} 3 {4 1} # {4 2} 3 {4 3} # {4 4} 3 {4 5} # {4 6} 3 {4 7} # {4 8} 3 {4 9} # {4 10} 3 {4 11} # {4 12} 3 {4 13} # {4 14} 3 {4 15} # {4 16} 3 {4 17} # {4 18} 3 {4 19} # {4 20} 3 {4 21} # {4 22} 3 {4 23} # {4 24} 3 {4 25} # {4 26} 3 {4 27} # {4 28} 3 {4 29} # {4 30} 3 {4 31} # {4 32} 3 {4 33} # {4 34} 3 {4 35} # {4 36} 3 {4 37} # {4 38} 3 {4 39} # {4 40} 3 {4 41} # {4 42} 3 {4 43} # {4 44} 3 {4 45} # {4 46} 3 {4 47} # {4 48} 3 {4 49} # {4 50} 3 {4 51} # {4 52} 3 {4 53} # {4 54} 3 {4 55} # {4 56} 3 {4 57} # {4 58} 3 {4 59} # {4 60} 3 {4 61} # {4 62} 3 {4 63} # {5 0} 4 {5 1} {$} {5 2} 4 {5 3} {$} {5 4} 4 {5 5} {$} {5 6} 4 {5 7} {$} {5 8} 4 {5 9} {$} {5 10} 4 {5 11} {$} {5 12} 4 {5 13} {$} {5 14} 4 {5 15} {$} {5 16} 4 {5 17} {$} {5 18} 4 {5 19} {$} {5 20} 4 {5 21} {$} {5 22} 4 {5 23} {$} {5 24} 4 {5 25} {$} {5 26} 4 {5 27} {$} {5 28} 4 {5 29} {$} {5 30} 4 {5 31} {$} {5 32} 4 {5 33} {$} {5 34} 4 {5 35} {$} {5 36} 4 {5 37} {$} {5 38} 4 {5 39} {$} {5 40} 4 {5 41} {$} {5 42} 4 {5 43} {$} {5 44} 4 {5 45} {$} {5 46} 4 {5 47} {$} {5 48} 4 {5 49} {$} {5 50} 4 {5 51} {$} {5 52} 4 {5 53} {$} {5 54} 4 {5 55} {$} {5 56} 4 {5 57} {$} {5 58} 4 {5 59} {$} {5 60} 4 {5 61} {$} {5 62} 4 {5 63} {$} {6 0} 5 {6 1} % {6 2} 5 {6 3} % {6 4} 5 {6 5} % {6 6} 5 {6 7} % {6 8} 5 {6 9} % {6 10} 5 {6 11} % {6 12} 5 {6 13} % {6 14} 5 {6 15} % {6 16} 5 {6 17} % {6 18} 5 {6 19} % {6 20} 5 {6 21} % {6 22} 5 {6 23} % {6 24} 5 {6 25} % {6 26} 5 {6 27} % {6 28} 5 {6 29} % {6 30} 5 {6 31} % {6 32} 5 {6 33} % {6 34} 5 {6 35} % {6 36} 5 {6 37} % {6 38} 5 {6 39} % {6 40} 5 {6 41} % {6 42} 5 {6 43} % {6 44} 5 {6 45} % {6 46} 5 {6 47} % {6 48} 5 {6 49} % {6 50} 5 {6 51} % {6 52} 5 {6 53} % {6 54} 5 {6 55} % {6 56} 5 {6 57} % {6 58} 5 {6 59} % {6 60} 5 {6 61} % {6 62} 5 {6 63} % {7 0} 6 {7 1} ^ {7 2} 6 {7 3} ^ {7 4} 6 {7 5} ^ {7 6} 6 {7 7} ^ {7 8} 6 {7 9} ^ {7 10} 6 {7 11} ^ {7 12} 6 {7 13} ^ {7 14} 6 {7 15} ^ {7 16} 6 {7 17} ^ {7 18} 6 {7 19} ^ {7 20} 6 {7 21} ^ {7 22} 6 {7 23} ^ {7 24} 6 {7 25} ^ {7 26} 6 {7 27} ^ {7 28} 6 {7 29} ^ {7 30} 6 {7 31} ^ {8 0} 7 {8 1} & {8 2} 7 {8 3} & {8 4} 7 {8 5} & {8 6} 7 {8 7} & {8 8} 7 {8 9} & {8 10} 7 {8 11} & {8 12} 7 {8 13} & {8 14} 7 {8 15} & {8 16} 7 {8 17} & {8 18} 7 {8 19} & {8 20} 7 {8 21} & {8 22} 7 {8 23} & {8 24} 7 {8 25} & {8 26} 7 {8 27} & {8 28} 7 {8 29} & {8 30} 7 {8 31} & {8 32} 7 {8 33} & {8 34} 7 {8 35} & {8 36} 7 {8 37} & {8 38} 7 {8 39} & {8 40} 7 {8 41} & {8 42} 7 {8 43} & {8 44} 7 {8 45} & {8 46} 7 {8 47} & {8 48} 7 {8 49} & {8 50} 7 {8 51} & {8 52} 7 {8 53} & {8 54} 7 {8 55} & {8 56} 7 {8 57} & {8 58} 7 {8 59} & {8 60} 7 {8 61} & {8 62} 7 {8 63} & {9 0} 8 {9 1} * {9 2} 8 {9 3} * {9 4} 8 {9 5} * {9 6} 8 {9 7} * {9 8} 8 {9 9} * {9 10} 8 {9 11} * {9 12} 8 {9 13} * {9 14} 8 {9 15} * {9 16} 8 {9 17} * {9 18} 8 {9 19} * {9 20} 8 {9 21} * {9 22} 8 {9 23} * {9 24} 8 {9 25} * {9 26} 8 {9 27} * {9 28} 8 {9 29} * {9 30} 8 {9 31} * {9 32} 8 {9 33} * {9 34} 8 {9 35} * {9 36} 8 {9 37} * {9 38} 8 {9 39} * {9 40} 8 {9 41} * {9 42} 8 {9 43} * {9 44} 8 {9 45} * {9 46} 8 {9 47} * {9 48} 8 {9 49} * {9 50} 8 {9 51} * {9 52} 8 {9 53} * {9 54} 8 {9 55} * {9 56} 8 {9 57} * {9 58} 8 {9 59} * {9 60} 8 {9 61} * {9 62} 8 {9 63} * {10 0} 9 {10 1} ( {10 2} 9 {10 3} ( {10 4} 9 {10 5} ( {10 6} 9 {10 7} ( {10 8} 9 {10 9} ( {10 10} 9 {10 11} ( {10 12} 9 {10 13} ( {10 14} 9 {10 15} ( {10 16} 9 {10 17} ( {10 18} 9 {10 19} ( {10 20} 9 {10 21} ( {10 22} 9 {10 23} ( {10 24} 9 {10 25} ( {10 26} 9 {10 27} ( {10 28} 9 {10 29} ( {10 30} 9 {10 31} ( {10 32} 9 {10 33} ( {10 34} 9 {10 35} ( {10 36} 9 {10 37} ( {10 38} 9 {10 39} ( {10 40} 9 {10 41} ( {10 42} 9 {10 43} ( {10 44} 9 {10 45} ( {10 46} 9 {10 47} ( {10 48} 9 {10 49} ( {10 50} 9 {10 51} ( {10 52} 9 {10 53} ( {10 54} 9 {10 55} ( {10 56} 9 {10 57} ( {10 58} 9 {10 59} ( {10 60} 9 {10 61} ( {10 62} 9 {10 63} ( {11 0} 0 {11 1} ) {11 2} 0 {11 3} ) {11 4} 0 {11 5} ) {11 6} 0 {11 7} ) {11 8} 0 {11 9} ) {11 10} 0 {11 11} ) {11 12} 0 {11 13} ) {11 14} 0 {11 15} ) {11 16} 0 {11 17} ) {11 18} 0 {11 19} ) {11 20} 0 {11 21} ) {11 22} 0 {11 23} ) {11 24} 0 {11 25} ) {11 26} 0 {11 27} ) {11 28} 0 {11 29} ) {11 30} 0 {11 31} ) {11 32} 0 {11 33} ) {11 34} 0 {11 35} ) {11 36} 0 {11 37} ) {11 38} 0 {11 39} ) {11 40} 0 {11 41} ) {11 42} 0 {11 43} ) {11 44} 0 {11 45} ) {11 46} 0 {11 47} ) {11 48} 0 {11 49} ) {11 50} 0 {11 51} ) {11 52} 0 {11 53} ) {11 54} 0 {11 55} ) {11 56} 0 {11 57} ) {11 58} 0 {11 59} ) {11 60} 0 {11 61} ) {11 62} 0 {11 63} ) {12 0} - {12 1} _ {12 2} - {12 3} _ {12 4} - {12 5} _ {12 6} - {12 7} _ {12 8} - {12 9} _ {12 10} - {12 11} _ {12 12} - {12 13} _ {12 14} - {12 15} _ {12 16} - {12 17} _ {12 18} - {12 19} _ {12 20} - {12 21} _ {12 22} - {12 23} _ {12 24} - {12 25} _ {12 26} - {12 27} _ {12 28} - {12 29} _ {12 30} - {12 31} _ {13 0} = {13 1} + {13 2} = {13 3} + {13 4} = {13 5} + {13 6} = {13 7} + {13 8} = {13 9} + {13 10} = {13 11} + {13 12} = {13 13} + {13 14} = {13 15} + {13 16} = {13 17} + {13 18} = {13 19} + {13 20} = {13 21} + {13 22} = {13 23} + {13 24} = {13 25} + {13 26} = {13 27} + {13 28} = {13 29} + {13 30} = {13 31} + {13 32} = {13 33} + {13 34} = {13 35} + {13 36} = {13 37} + {13 38} = {13 39} + {13 40} = {13 41} + {13 42} = {13 43} + {13 44} = {13 45} + {13 46} = {13 47} + {13 48} = {13 49} + {13 50} = {13 51} + {13 52} = {13 53} + {13 54} = {13 55} + {13 56} = {13 57} + {13 58} = {13 59} + {13 60} = {13 61} + {13 62} = {13 63} + {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} q {16 5} Q {16 6} q {16 7} Q {16 8} q {16 9} Q {16 10} q {16 11} Q {16 12} q {16 13} Q {16 14} q {16 15} Q {16 16} Q {16 17} q {16 18} Q {16 19} q {16 20} Q {16 21} q {16 22} Q {16 23} q {16 24} Q {16 25} q {16 26} Q {16 27} q {16 28} Q {16 29} q {16 30} Q {16 31} q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} w {17 5} W {17 6} w {17 7} W {17 8} w {17 9} W {17 10} w {17 11} W {17 12} w {17 13} W {17 14} w {17 15} W {17 16} W {17 17} w {17 18} W {17 19} w {17 20} W {17 21} w {17 22} W {17 23} w {17 24} W {17 25} w {17 26} W {17 27} w {17 28} W {17 29} w {17 30} W {17 31} w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} e {18 5} E {18 6} e {18 7} E {18 8} e {18 9} E {18 10} e {18 11} E {18 12} e {18 13} E {18 14} e {18 15} E {18 16} E {18 17} e {18 18} E {18 19} e {18 20} E {18 21} e {18 22} E {18 23} e {18 24} E {18 25} e {18 26} E {18 27} e {18 28} E {18 29} e {18 30} E {18 31} e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} r {19 5} R {19 6} r {19 7} R {19 8} r {19 9} R {19 10} r {19 11} R {19 12} r {19 13} R {19 14} r {19 15} R {19 16} R {19 17} r {19 18} R {19 19} r {19 20} R {19 21} r {19 22} R {19 23} r {19 24} R {19 25} r {19 26} R {19 27} r {19 28} R {19 29} r {19 30} R {19 31} r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} t {20 5} T {20 6} t {20 7} T {20 8} t {20 9} T {20 10} t {20 11} T {20 12} t {20 13} T {20 14} t {20 15} T {20 16} T {20 17} t {20 18} T {20 19} t {20 20} T {20 21} t {20 22} T {20 23} t {20 24} T {20 25} t {20 26} T {20 27} t {20 28} T {20 29} t {20 30} T {20 31} t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} y {21 5} Y {21 6} y {21 7} Y {21 8} y {21 9} Y {21 10} y {21 11} Y {21 12} y {21 13} Y {21 14} y {21 15} Y {21 16} Y {21 17} y {21 18} Y {21 19} y {21 20} Y {21 21} y {21 22} Y {21 23} y {21 24} Y {21 25} y {21 26} Y {21 27} y {21 28} Y {21 29} y {21 30} Y {21 31} y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} u {22 5} U {22 6} u {22 7} U {22 8} u {22 9} U {22 10} u {22 11} U {22 12} u {22 13} U {22 14} u {22 15} U {22 16} U {22 17} u {22 18} U {22 19} u {22 20} U {22 21} u {22 22} U {22 23} u {22 24} U {22 25} u {22 26} U {22 27} u {22 28} U {22 29} u {22 30} U {22 31} u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} i {23 5} I {23 6} i {23 7} I {23 8} i {23 9} I {23 10} i {23 11} I {23 12} i {23 13} I {23 14} i {23 15} I {23 16} I {23 17} i {23 18} I {23 19} i {23 20} I {23 21} i {23 22} I {23 23} i {23 24} I {23 25} i {23 26} I {23 27} i {23 28} I {23 29} i {23 30} I {23 31} i {24 0} o {24 1} O {24 2} o {24 3} O {24 4} o {24 5} O {24 6} o {24 7} O {24 8} o {24 9} O {24 10} o {24 11} O {24 12} o {24 13} O {24 14} o {24 15} O {24 16} O {24 17} o {24 18} O {24 19} o {24 20} O {24 21} o {24 22} O {24 23} o {24 24} O {24 25} o {24 26} O {24 27} o {24 28} O {24 29} o {24 30} O {24 31} o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} p {25 5} P {25 6} p {25 7} P {25 8} p {25 9} P {25 10} p {25 11} P {25 12} p {25 13} P {25 14} p {25 15} P {25 16} P {25 17} p {25 18} P {25 19} p {25 20} P {25 21} p {25 22} P {25 23} p {25 24} P {25 25} p {25 26} P {25 27} p {25 28} P {25 29} p {25 30} P {25 31} p {26 0} {[} {26 1} \{ {26 2} {[} {26 3} \{ {26 4} {[} {26 5} \{ {26 6} {[} {26 7} \{ {26 8} {[} {26 9} \{ {26 10} {[} {26 11} \{ {26 12} {[} {26 13} \{ {26 14} {[} {26 15} \{ {26 16} {[} {26 17} \{ {26 18} {[} {26 19} \{ {26 20} {[} {26 21} \{ {26 22} {[} {26 23} \{ {26 24} {[} {26 25} \{ {26 26} {[} {26 27} \{ {26 28} {[} {26 29} \{ {26 30} {[} {26 31} \{ {27 0} \] {27 1} \} {27 2} \] {27 3} \} {27 4} \] {27 5} \} {27 6} \] {27 7} \} {27 8} \] {27 9} \} {27 10} \] {27 11} \} {27 12} \] {27 13} \} {27 14} \] {27 15} \} {27 16} \] {27 17} \} {27 18} \] {27 19} \} {27 20} \] {27 21} \} {27 22} \] {27 23} \} {27 24} \] {27 25} \} {27 26} \] {27 27} \} {27 28} \] {27 29} \} {27 30} \] {27 31} \} {30 0} a {30 1} A {30 2} a {30 3} A {30 4} a {30 5} A {30 6} a {30 7} A {30 8} a {30 9} A {30 10} a {30 11} A {30 12} a {30 13} A {30 14} a {30 15} A {30 16} A {30 17} a {30 18} A {30 19} a {30 20} A {30 21} a {30 22} A {30 23} a {30 24} A {30 25} a {30 26} A {30 27} a {30 28} A {30 29} a {30 30} A {30 31} a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} s {31 5} S {31 6} s {31 7} S {31 8} s {31 9} S {31 10} s {31 11} S {31 12} s {31 13} S {31 14} s {31 15} S {31 16} S {31 17} s {31 18} S {31 19} s {31 20} S {31 21} s {31 22} S {31 23} s {31 24} S {31 25} s {31 26} S {31 27} s {31 28} S {31 29} s {31 30} S {31 31} s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} d {32 5} D {32 6} d {32 7} D {32 8} d {32 9} D {32 10} d {32 11} D {32 12} d {32 13} D {32 14} d {32 15} D {32 16} D {32 17} d {32 18} D {32 19} d {32 20} D {32 21} d {32 22} D {32 23} d {32 24} D {32 25} d {32 26} D {32 27} d {32 28} D {32 29} d {32 30} D {32 31} d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} f {33 5} F {33 6} f {33 7} F {33 8} f {33 9} F {33 10} f {33 11} F {33 12} f {33 13} F {33 14} f {33 15} F {33 16} F {33 17} f {33 18} F {33 19} f {33 20} F {33 21} f {33 22} F {33 23} f {33 24} F {33 25} f {33 26} F {33 27} f {33 28} F {33 29} f {33 30} F {33 31} f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} g {34 5} G {34 6} g {34 7} G {34 8} g {34 9} G {34 10} g {34 11} G {34 12} g {34 13} G {34 14} g {34 15} G {34 16} G {34 17} g {34 18} G {34 19} g {34 20} G {34 21} g {34 22} G {34 23} g {34 24} G {34 25} g {34 26} G {34 27} g {34 28} G {34 29} g {34 30} G {34 31} g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} h {35 5} H {35 6} h {35 7} H {35 8} h {35 9} H {35 10} h {35 11} H {35 12} h {35 13} H {35 14} h {35 15} H {35 16} H {35 17} h {35 18} H {35 19} h {35 20} H {35 21} h {35 22} H {35 23} h {35 24} H {35 25} h {35 26} H {35 27} h {35 28} H {35 29} h {35 30} H {35 31} h {36 0} j {36 1} J {36 2} j {36 3} J {36 4} j {36 5} J {36 6} j {36 7} J {36 8} j {36 9} J {36 10} j {36 11} J {36 12} j {36 13} J {36 14} j {36 15} J {36 16} J {36 17} j {36 18} J {36 19} j {36 20} J {36 21} j {36 22} J {36 23} j {36 24} J {36 25} j {36 26} J {36 27} j {36 28} J {36 29} j {36 30} J {36 31} j {37 0} k {37 1} K {37 2} k {37 3} K {37 4} k {37 5} K {37 6} k {37 7} K {37 8} k {37 9} K {37 10} k {37 11} K {37 12} k {37 13} K {37 14} k {37 15} K {37 16} K {37 17} k {37 18} K {37 19} k {37 20} K {37 21} k {37 22} K {37 23} k {37 24} K {37 25} k {37 26} K {37 27} k {37 28} K {37 29} k {37 30} K {37 31} k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} l {38 5} L {38 6} l {38 7} L {38 8} l {38 9} L {38 10} l {38 11} L {38 12} l {38 13} L {38 14} l {38 15} L {38 16} L {38 17} l {38 18} L {38 19} l {38 20} L {38 21} l {38 22} L {38 23} l {38 24} L {38 25} l {38 26} L {38 27} l {38 28} L {38 29} l {38 30} L {38 31} l {39 0} {;} {39 1} : {39 2} {;} {39 3} : {39 4} {;} {39 5} : {39 6} {;} {39 7} : {39 8} {;} {39 9} : {39 10} {;} {39 11} : {39 12} {;} {39 13} : {39 14} {;} {39 15} : {39 16} {;} {39 17} : {39 18} {;} {39 19} : {39 20} {;} {39 21} : {39 22} {;} {39 23} : {39 24} {;} {39 25} : {39 26} {;} {39 27} : {39 28} {;} {39 29} : {39 30} {;} {39 31} : {39 32} {;} {39 33} : {39 34} {;} {39 35} : {39 36} {;} {39 37} : {39 38} {;} {39 39} : {39 40} {;} {39 41} : {39 42} {;} {39 43} : {39 44} {;} {39 45} : {39 46} {;} {39 47} : {39 48} {;} {39 49} : {39 50} {;} {39 51} : {39 52} {;} {39 53} : {39 54} {;} {39 55} : {39 56} {;} {39 57} : {39 58} {;} {39 59} : {39 60} {;} {39 61} : {39 62} {;} {39 63} : {40 0} ' {40 1} {"} {40 2} ' {40 3} {"} {40 4} ' {40 5} {"} {40 6} ' {40 7} {"} {40 8} ' {40 9} {"} {40 10} ' {40 11} {"} {40 12} ' {40 13} {"} {40 14} ' {40 15} {"} {40 16} ' {40 17} {"} {40 18} ' {40 19} {"} {40 20} ' {40 21} {"} {40 22} ' {40 23} {"} {40 24} ' {40 25} {"} {40 26} ' {40 27} {"} {40 28} ' {40 29} {"} {40 30} ' {40 31} {"} {40 32} ' {40 33} {"} {40 34} ' {40 35} {"} {40 36} ' {40 37} {"} {40 38} ' {40 39} {"} {40 40} ' {40 41} {"} {40 42} ' {40 43} {"} {40 44} ' {40 45} {"} {40 46} ' {40 47} {"} {40 48} ' {40 49} {"} {40 50} ' {40 51} {"} {40 52} ' {40 53} {"} {40 54} ' {40 55} {"} {40 56} ' {40 57} {"} {40 58} ' {40 59} {"} {40 60} ' {40 61} {"} {40 62} ' {40 63} {"} {41 0} ` {41 1} ~ {41 2} ` {41 3} ~ {41 4} ` {41 5} ~ {41 6} ` {41 7} ~ {41 8} ` {41 9} ~ {41 10} ` {41 11} ~ {41 12} ` {41 13} ~ {41 14} ` {41 15} ~ {41 16} ` {41 17} ~ {41 18} ` {41 19} ~ {41 20} ` {41 21} ~ {41 22} ` {41 23} ~ {41 24} ` {41 25} ~ {41 26} ` {41 27} ~ {41 28} ` {41 29} ~ {41 30} ` {41 31} ~ {43 0} \\ {43 1} | {43 2} \\ {43 3} | {43 4} \\ {43 5} | {43 6} \\ {43 7} | {43 8} \\ {43 9} | {43 10} \\ {43 11} | {43 12} \\ {43 13} | {43 14} \\ {43 15} | {43 16} \\ {43 17} | {43 18} \\ {43 19} | {43 20} \\ {43 21} | {43 22} \\ {43 23} | {43 24} \\ {43 25} | {43 26} \\ {43 27} | {43 28} \\ {43 29} | {43 30} \\ {43 31} | {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} z {44 5} Z {44 6} z {44 7} Z {44 8} z {44 9} Z {44 10} z {44 11} Z {44 12} z {44 13} Z {44 14} z {44 15} Z {44 16} Z {44 17} z {44 18} Z {44 19} z {44 20} Z {44 21} z {44 22} Z {44 23} z {44 24} Z {44 25} z {44 26} Z {44 27} z {44 28} Z {44 29} z {44 30} Z {44 31} z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} x {45 5} X {45 6} x {45 7} X {45 8} x {45 9} X {45 10} x {45 11} X {45 12} x {45 13} X {45 14} x {45 15} X {45 16} X {45 17} x {45 18} X {45 19} x {45 20} X {45 21} x {45 22} X {45 23} x {45 24} X {45 25} x {45 26} X {45 27} x {45 28} X {45 29} x {45 30} X {45 31} x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} c {46 5} C {46 6} c {46 7} C {46 8} c {46 9} C {46 10} c {46 11} C {46 12} c {46 13} C {46 14} c {46 15} C {46 16} C {46 17} c {46 18} C {46 19} c {46 20} C {46 21} c {46 22} C {46 23} c {46 24} C {46 25} c {46 26} C {46 27} c {46 28} C {46 29} c {46 30} C {46 31} c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} v {47 5} V {47 6} v {47 7} V {47 8} v {47 9} V {47 10} v {47 11} V {47 12} v {47 13} V {47 14} v {47 15} V {47 16} V {47 17} v {47 18} V {47 19} v {47 20} V {47 21} v {47 22} V {47 23} v {47 24} V {47 25} v {47 26} V {47 27} v {47 28} V {47 29} v {47 30} V {47 31} v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} b {48 5} B {48 6} b {48 7} B {48 8} b {48 9} B {48 10} b {48 11} B {48 12} b {48 13} B {48 14} b {48 15} B {48 16} B {48 17} b {48 18} B {48 19} b {48 20} B {48 21} b {48 22} B {48 23} b {48 24} B {48 25} b {48 26} B {48 27} b {48 28} B {48 29} b {48 30} B {48 31} b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} n {49 5} N {49 6} n {49 7} N {49 8} n {49 9} N {49 10} n {49 11} N {49 12} n {49 13} N {49 14} n {49 15} N {49 16} N {49 17} n {49 18} N {49 19} n {49 20} N {49 21} n {49 22} N {49 23} n {49 24} N {49 25} n {49 26} N {49 27} n {49 28} N {49 29} n {49 30} N {49 31} n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} m {50 5} M {50 6} m {50 7} M {50 8} m {50 9} M {50 10} m {50 11} M {50 12} m {50 13} M {50 14} m {50 15} M {50 16} M {50 17} m {50 18} M {50 19} m {50 20} M {50 21} m {50 22} M {50 23} m {50 24} M {50 25} m {50 26} M {50 27} m {50 28} M {50 29} m {50 30} M {50 31} m {51 0} , {51 1} < {51 2} , {51 3} < {51 4} , {51 5} < {51 6} , {51 7} < {51 8} , {51 9} < {51 10} , {51 11} < {51 12} , {51 13} < {51 14} , {51 15} < {51 16} , {51 17} < {51 18} , {51 19} < {51 20} , {51 21} < {51 22} , {51 23} < {51 24} , {51 25} < {51 26} , {51 27} < {51 28} , {51 29} < {51 30} , {51 31} < {51 32} , {51 33} < {51 34} , {51 35} < {51 36} , {51 37} < {51 38} , {51 39} < {51 40} , {51 41} < {51 42} , {51 43} < {51 44} , {51 45} < {51 46} , {51 47} < {51 48} , {51 49} < {51 50} , {51 51} < {51 52} , {51 53} < {51 54} , {51 55} < {51 56} , {51 57} < {51 58} , {51 59} < {51 60} , {51 61} < {51 62} , {51 63} < {52 0} . {52 1} > {52 2} . {52 3} > {52 4} . {52 5} > {52 6} . {52 7} > {52 8} . {52 9} > {52 10} . {52 11} > {52 12} . {52 13} > {52 14} . {52 15} > {52 16} . {52 17} > {52 18} . {52 19} > {52 20} . {52 21} > {52 22} . {52 23} > {52 24} . {52 25} > {52 26} . {52 27} > {52 28} . {52 29} > {52 30} . {52 31} > {53 0} / {53 1} ? {53 2} / {53 3} ? {53 4} / {53 5} ? {53 6} / {53 7} ? {53 8} / {53 9} ? {53 10} / {53 11} ? {53 12} / {53 13} ? {53 14} / {53 15} ? {53 16} / {53 17} ? {53 18} / {53 19} ? {53 20} / {53 21} ? {53 22} / {53 23} ? {53 24} / {53 25} ? {53 26} / {53 27} ? {53 28} / {53 29} ? {53 30} / {53 31} ? {57 0} { } {57 1} { } {57 2} { } {57 3} { } {57 4} { } {57 5} { } {57 6} { } {57 7} { } {57 8} { } {57 9} { } {57 10} { } {57 11} { } {57 12} { } {57 13} { } {57 14} { } {57 15} { } {57 16} { } {57 17} { } {57 18} { } {57 19} { } {57 20} { } {57 21} { } {57 22} { } {57 23} { } {57 24} { } {57 25} { } {57 26} { } {57 27} { } {57 28} { } {57 29} { } {57 30} { } {57 31} { } {86 0} < {86 1} > {86 2} | {86 3} ¦ {86 4} > {86 5} < {86 6} > {86 7} | {86 8} ¦ {86 9} > {86 10} < {86 11} > {86 12} | {86 13} ¦ {86 14} > {86 15} < {86 16} > {86 17} | {86 18} ¦ {86 19} > {86 20} < {86 21} > {86 22} | {86 23} ¦ {86 24} > {86 25} < {86 26} > {86 27} | {86 28} ¦ {86 29} > {86 30} < {86 31} > {86 32} | {86 33} ¦ {86 34} > {86 35} < {86 36} > {86 37} | {86 38} ¦ {86 39} >}} keyboardFileno 179 grabber <C:cfilezxlzNz> cc ::<reference.<C______>.00000000000000000002>}}
when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd locale ()when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd locale /locale/ \n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}} {keyboard /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd} {keyboardChannel ::aio.handle10 KEY_STATES {up down repeat} defaultKeymap {{{1 0} Escape {1 1} Escape {1 2} Escape {1 3} Escape {1 4} Escape {1 5} Escape {1 6} Escape {1 7} Escape {1 8} Meta_Escape {1 9} Meta_Escape {1 10} Meta_Escape {1 11} Meta_Escape {1 12} Meta_Escape {1 13} Meta_Escape {1 14} Meta_Escape {1 15} Meta_Escape {1 16} Escape {1 17} Escape {1 18} Escape {1 19} Escape {1 20} Escape {1 21} Escape {1 22} Escape {1 23} Escape {1 24} Meta_Escape {1 25} Meta_Escape {1 26} Meta_Escape {1 27} Meta_Escape {1 28} Meta_Escape {1 29} Meta_Escape {1 30} Meta_Escape {1 31} Meta_Escape {1 32} Escape {1 33} Escape {1 34} Escape {1 35} Escape {1 36} Escape {1 37} Escape {1 38} Escape {1 39} Escape {1 40} Meta_Escape {1 41} Meta_Escape {1 42} Meta_Escape {1 43} Meta_Escape {1 44} Meta_Escape {1 45} Meta_Escape {1 46} Meta_Escape {1 47} Meta_Escape {1 48} Escape {1 49} Escape {1 50} Escape {1 51} Escape {1 52} Escape {1 53} Escape {1 54} Escape {1 55} Escape {1 56} Meta_Escape {1 57} Meta_Escape {1 58} Meta_Escape {1 59} Meta_Escape {1 60} Meta_Escape {1 61} Meta_Escape {1 62} Meta_Escape {1 63} Meta_Escape {1 64} Escape {1 65} Escape {1 66} Escape {1 67} Escape {1 68} Escape {1 69} Escape {1 70} Escape {1 71} Escape {1 72} Meta_Escape {1 73} Meta_Escape {1 74} Meta_Escape {1 75} Meta_Escape {1 76} Meta_Escape {1 77} Meta_Escape {1 78} Meta_Escape {1 79} Meta_Escape {1 80} Escape {1 81} Escape {1 82} Escape {1 83} Escape {1 84} Escape {1 85} Escape {1 86} Escape {1 87} Escape {1 88} Meta_Escape {1 89} Meta_Escape {1 90} Meta_Escape {1 91} Meta_Escape {1 92} Meta_Escape {1 93} Meta_Escape {1 94} Meta_Escape {1 95} Meta_Escape {1 96} Escape {1 97} Escape {1 98} Escape {1 99} Escape {1 100} Escape {1 101} Escape {1 102} Escape {1 103} Escape {1 104} Meta_Escape {1 105} Meta_Escape {1 106} Meta_Escape {1 107} Meta_Escape {1 108} Meta_Escape {1 109} Meta_Escape {1 110} Meta_Escape {1 111} Meta_Escape {1 112} Escape {1 113} Escape {1 114} Escape {1 115} Escape {1 116} Escape {1 117} Escape {1 118} Escape {1 119} Escape {1 120} Meta_Escape {1 121} Meta_Escape {1 122} Meta_Escape {1 123} Meta_Escape {1 124} Meta_Escape {1 125} Meta_Escape {1 126} Meta_Escape {1 127} Meta_Escape {2 0} one {2 1} exclam {2 2} one {2 3} exclam {2 4} one {2 5} exclam {2 6} one {2 7} exclam {2 8} Meta_one {2 9} Meta_exclam {2 10} Meta_one {2 11} Meta_exclam {2 12} Meta_one {2 13} Meta_exclam {2 14} Meta_one {2 15} Meta_exclam {2 16} one {2 17} exclam {2 18} one {2 19} exclam {2 20} one {2 21} exclam {2 22} one {2 23} exclam {2 24} Meta_one {2 25} Meta_exclam {2 26} Meta_one {2 27} Meta_exclam {2 28} Meta_one {2 29} Meta_exclam {2 30} Meta_one {2 31} Meta_exclam {2 32} one {2 33} exclam {2 34} one {2 35} exclam {2 36} one {2 37} exclam {2 38} one {2 39} exclam {2 40} Meta_one {2 41} Meta_exclam {2 42} Meta_one {2 43} Meta_exclam {2 44} Meta_one {2 45} Meta_exclam {2 46} Meta_one {2 47} Meta_exclam {2 48} one {2 49} exclam {2 50} one {2 51} exclam {2 52} one {2 53} exclam {2 54} one {2 55} exclam {2 56} Meta_one {2 57} Meta_exclam {2 58} Meta_one {2 59} Meta_exclam {2 60} Meta_one {2 61} Meta_exclam {2 62} Meta_one {2 63} Meta_exclam {2 64} one {2 65} exclam {2 66} one {2 67} exclam {2 68} one {2 69} exclam {2 70} one {2 71} exclam {2 72} Meta_one {2 73} Meta_exclam {2 74} Meta_one {2 75} Meta_exclam {2 76} Meta_one {2 77} Meta_exclam {2 78} Meta_one {2 79} Meta_exclam {2 80} one {2 81} exclam {2 82} one {2 83} exclam {2 84} one {2 85} exclam {2 86} one {2 87} exclam {2 88} Meta_one {2 89} Meta_exclam {2 90} Meta_one {2 91} Meta_exclam {2 92} Meta_one {2 93} Meta_exclam {2 94} Meta_one {2 95} Meta_exclam {2 96} one {2 97} exclam {2 98} one {2 99} exclam {2 100} one {2 101} exclam {2 102} one {2 103} exclam {2 104} Meta_one {2 105} Meta_exclam {2 106} Meta_one {2 107} Meta_exclam {2 108} Meta_one {2 109} Meta_exclam {2 110} Meta_one {2 111} Meta_exclam {2 112} one {2 113} exclam {2 114} one {2 115} exclam {2 116} one {2 117} exclam {2 118} one {2 119} exclam {2 120} Meta_one {2 121} Meta_exclam {2 122} Meta_one {2 123} Meta_exclam {2 124} Meta_one {2 125} Meta_exclam {2 126} Meta_one {2 127} Meta_exclam {3 0} two {3 1} at {3 2} two {3 3} at {3 4} nul {3 5} nul {3 6} nul {3 7} nul {3 8} Meta_two {3 9} Meta_at {3 10} Meta_two {3 11} Meta_at {3 12} Meta_nul {3 13} Meta_nul {3 14} Meta_nul {3 15} Meta_nul {3 16} two {3 17} at {3 18} two {3 19} at {3 20} nul {3 21} nul {3 22} nul {3 23} nul {3 24} Meta_two {3 25} Meta_at {3 26} Meta_two {3 27} Meta_at {3 28} Meta_nul {3 29} Meta_nul {3 30} Meta_nul {3 31} Meta_nul {3 32} two {3 33} at {3 34} two {3 35} at {3 36} nul {3 37} nul {3 38} nul {3 39} nul {3 40} Meta_two {3 41} Meta_at {3 42} Meta_two {3 43} Meta_at {3 44} Meta_nul {3 45} Meta_nul {3 46} Meta_nul {3 47} Meta_nul {3 48} two {3 49} at {3 50} two {3 51} at {3 52} nul {3 53} nul {3 54} nul {3 55} nul {3 56} Meta_two {3 57} Meta_at {3 58} Meta_two {3 59} Meta_at {3 60} Meta_nul {3 61} Meta_nul {3 62} Meta_nul {3 63} Meta_nul {3 64} two {3 65} at {3 66} two {3 67} at {3 68} nul {3 69} nul {3 70} nul {3 71} nul {3 72} Meta_two {3 73} Meta_at {3 74} Meta_two {3 75} Meta_at {3 76} Meta_nul {3 77} Meta_nul {3 78} Meta_nul {3 79} Meta_nul {3 80} two {3 81} at {3 82} two {3 83} at {3 84} nul {3 85} nul {3 86} nul {3 87} nul {3 88} Meta_two {3 89} Meta_at {3 90} Meta_two {3 91} Meta_at {3 92} Meta_nul {3 93} Meta_nul {3 94} Meta_nul {3 95} Meta_nul {3 96} two {3 97} at {3 98} two {3 99} at {3 100} nul {3 101} nul {3 102} nul {3 103} nul {3 104} Meta_two {3 105} Meta_at {3 106} Meta_two {3 107} Meta_at {3 108} Meta_nul {3 109} Meta_nul {3 110} Meta_nul {3 111} Meta_nul {3 112} two {3 113} at {3 114} two {3 115} at {3 116} nul {3 117} nul {3 118} nul {3 119} nul {3 120} Meta_two {3 121} Meta_at {3 122} Meta_two {3 123} Meta_at {3 124} Meta_nul {3 125} Meta_nul {3 126} Meta_nul {3 127} Meta_nul {4 0} three {4 1} numbersign {4 2} three {4 3} numbersign {4 4} three {4 5} numbersign {4 6} three {4 7} numbersign {4 8} Meta_three {4 9} Meta_numbersign {4 10} Meta_three {4 11} Meta_numbersign {4 12} Meta_three {4 13} Meta_numbersign {4 14} Meta_three {4 15} Meta_numbersign {4 16} three {4 17} numbersign {4 18} three {4 19} numbersign {4 20} three {4 21} numbersign {4 22} three {4 23} numbersign {4 24} Meta_three {4 25} Meta_numbersign {4 26} Meta_three {4 27} Meta_numbersign {4 28} Meta_three {4 29} Meta_numbersign {4 30} Meta_three {4 31} Meta_numbersign {4 32} three {4 33} numbersign {4 34} three {4 35} numbersign {4 36} three {4 37} numbersign {4 38} three {4 39} numbersign {4 40} Meta_three {4 41} Meta_numbersign {4 42} Meta_three {4 43} Meta_numbersign {4 44} Meta_three {4 45} Meta_numbersign {4 46} Meta_three {4 47} Meta_numbersign {4 48} three {4 49} numbersign {4 50} three {4 51} numbersign {4 52} three {4 53} numbersign {4 54} three {4 55} numbersign {4 56} Meta_three {4 57} Meta_numbersign {4 58} Meta_three {4 59} Meta_numbersign {4 60} Meta_three {4 61} Meta_numbersign {4 62} Meta_three {4 63} Meta_numbersign {4 64} three {4 65} numbersign {4 66} three {4 67} numbersign {4 68} three {4 69} numbersign {4 70} three {4 71} numbersign {4 72} Meta_three {4 73} Meta_numbersign {4 74} Meta_three {4 75} Meta_numbersign {4 76} Meta_three {4 77} Meta_numbersign {4 78} Meta_three {4 79} Meta_numbersign {4 80} three {4 81} numbersign {4 82} three {4 83} numbersign {4 84} three {4 85} numbersign {4 86} three {4 87} numbersign {4 88} Meta_three {4 89} Meta_numbersign {4 90} Meta_three {4 91} Meta_numbersign {4 92} Meta_three {4 93} Meta_numbersign {4 94} Meta_three {4 95} Meta_numbersign {4 96} three {4 97} numbersign {4 98} three {4 99} numbersign {4 100} three {4 101} numbersign {4 102} three {4 103} numbersign {4 104} Meta_three {4 105} Meta_numbersign {4 106} Meta_three {4 107} Meta_numbersign {4 108} Meta_three {4 109} Meta_numbersign {4 110} Meta_three {4 111} Meta_numbersign {4 112} three {4 113} numbersign {4 114} three {4 115} numbersign {4 116} three {4 117} numbersign {4 118} three {4 119} numbersign {4 120} Meta_three {4 121} Meta_numbersign {4 122} Meta_three {4 123} Meta_numbersign {4 124} Meta_three {4 125} Meta_numbersign {4 126} Meta_three {4 127} Meta_numbersign {5 0} four {5 1} dollar {5 2} four {5 3} dollar {5 4} four {5 5} dollar {5 6} four {5 7} dollar {5 8} Meta_four {5 9} Meta_dollar {5 10} Meta_four {5 11} Meta_dollar {5 12} Meta_four {5 13} Meta_dollar {5 14} Meta_four {5 15} Meta_dollar {5 16} four {5 17} dollar {5 18} four {5 19} dollar {5 20} four {5 21} dollar {5 22} four {5 23} dollar {5 24} Meta_four {5 25} Meta_dollar {5 26} Meta_four {5 27} Meta_dollar {5 28} Meta_four {5 29} Meta_dollar {5 30} Meta_four {5 31} Meta_dollar {5 32} four {5 33} dollar {5 34} four {5 35} dollar {5 36} four {5 37} dollar {5 38} four {5 39} dollar {5 40} Meta_four {5 41} Meta_dollar {5 42} Meta_four {5 43} Meta_dollar {5 44} Meta_four {5 45} Meta_dollar {5 46} Meta_four {5 47} Meta_dollar {5 48} four {5 49} dollar {5 50} four {5 51} dollar {5 52} four {5 53} dollar {5 54} four {5 55} dollar {5 56} Meta_four {5 57} Meta_dollar {5 58} Meta_four {5 59} Meta_dollar {5 60} Meta_four {5 61} Meta_dollar {5 62} Meta_four {5 63} Meta_dollar {5 64} four {5 65} dollar {5 66} four {5 67} dollar {5 68} four {5 69} dollar {5 70} four {5 71} dollar {5 72} Meta_four {5 73} Meta_dollar {5 74} Meta_four {5 75} Meta_dollar {5 76} Meta_four {5 77} Meta_dollar {5 78} Meta_four {5 79} Meta_dollar {5 80} four {5 81} dollar {5 82} four {5 83} dollar {5 84} four {5 85} dollar {5 86} four {5 87} dollar {5 88} Meta_four {5 89} Meta_dollar {5 90} Meta_four {5 91} Meta_dollar {5 92} Meta_four {5 93} Meta_dollar {5 94} Meta_four {5 95} Meta_dollar {5 96} four {5 97} dollar {5 98} four {5 99} dollar {5 100} four {5 101} dollar {5 102} four {5 103} dollar {5 104} Meta_four {5 105} Meta_dollar {5 106} Meta_four {5 107} Meta_dollar {5 108} Meta_four {5 109} Meta_dollar {5 110} Meta_four {5 111} Meta_dollar {5 112} four {5 113} dollar {5 114} four {5 115} dollar {5 116} four {5 117} dollar {5 118} four {5 119} dollar {5 120} Meta_four {5 121} Meta_dollar {5 122} Meta_four {5 123} Meta_dollar {5 124} Meta_four {5 125} Meta_dollar {5 126} Meta_four {5 127} Meta_dollar {6 0} five {6 1} percent {6 2} five {6 3} percent {6 4} five {6 5} percent {6 6} five {6 7} percent {6 8} Meta_five {6 9} Meta_percent {6 10} Meta_five {6 11} Meta_percent {6 12} Meta_five {6 13} Meta_percent {6 14} Meta_five {6 15} Meta_percent {6 16} five {6 17} percent {6 18} five {6 19} percent {6 20} five {6 21} percent {6 22} five {6 23} percent {6 24} Meta_five {6 25} Meta_percent {6 26} Meta_five {6 27} Meta_percent {6 28} Meta_five {6 29} Meta_percent {6 30} Meta_five {6 31} Meta_percent {6 32} five {6 33} percent {6 34} five {6 35} percent {6 36} five {6 37} percent {6 38} five {6 39} percent {6 40} Meta_five {6 41} Meta_percent {6 42} Meta_five {6 43} Meta_percent {6 44} Meta_five {6 45} Meta_percent {6 46} Meta_five {6 47} Meta_percent {6 48} five {6 49} percent {6 50} five {6 51} percent {6 52} five {6 53} percent {6 54} five {6 55} percent {6 56} Meta_five {6 57} Meta_percent {6 58} Meta_five {6 59} Meta_percent {6 60} Meta_five {6 61} Meta_percent {6 62} Meta_five {6 63} Meta_percent {6 64} five {6 65} percent {6 66} five {6 67} percent {6 68} five {6 69} percent {6 70} five {6 71} percent {6 72} Meta_five {6 73} Meta_percent {6 74} Meta_five {6 75} Meta_percent {6 76} Meta_five {6 77} Meta_percent {6 78} Meta_five {6 79} Meta_percent {6 80} five {6 81} percent {6 82} five {6 83} percent {6 84} five {6 85} percent {6 86} five {6 87} percent {6 88} Meta_five {6 89} Meta_percent {6 90} Meta_five {6 91} Meta_percent {6 92} Meta_five {6 93} Meta_percent {6 94} Meta_five {6 95} Meta_percent {6 96} five {6 97} percent {6 98} five {6 99} percent {6 100} five {6 101} percent {6 102} five {6 103} percent {6 104} Meta_five {6 105} Meta_percent {6 106} Meta_five {6 107} Meta_percent {6 108} Meta_five {6 109} Meta_percent {6 110} Meta_five {6 111} Meta_percent {6 112} five {6 113} percent {6 114} five {6 115} percent {6 116} five {6 117} percent {6 118} five {6 119} percent {6 120} Meta_five {6 121} Meta_percent {6 122} Meta_five {6 123} Meta_percent {6 124} Meta_five {6 125} Meta_percent {6 126} Meta_five {6 127} Meta_percent {7 0} six {7 1} asciicircum {7 2} six {7 3} asciicircum {7 4} Control_asciicircum {7 5} Control_asciicircum {7 6} Control_asciicircum {7 7} Control_asciicircum {7 8} Meta_six {7 9} Meta_asciicircum {7 10} Meta_six {7 11} Meta_asciicircum {7 12} Meta_Control_asciicircum {7 13} Meta_Control_asciicircum {7 14} Meta_Control_asciicircum {7 15} Meta_Control_asciicircum {7 16} six {7 17} asciicircum {7 18} six {7 19} asciicircum {7 20} Control_asciicircum {7 21} Control_asciicircum {7 22} Control_asciicircum {7 23} Control_asciicircum {7 24} Meta_six {7 25} Meta_asciicircum {7 26} Meta_six {7 27} Meta_asciicircum {7 28} Meta_Control_asciicircum {7 29} Meta_Control_asciicircum {7 30} Meta_Control_asciicircum {7 31} Meta_Control_asciicircum {7 32} six {7 33} asciicircum {7 34} six {7 35} asciicircum {7 36} Control_asciicircum {7 37} Control_asciicircum {7 38} Control_asciicircum {7 39} Control_asciicircum {7 40} Meta_six {7 41} Meta_asciicircum {7 42} Meta_six {7 43} Meta_asciicircum {7 44} Meta_Control_asciicircum {7 45} Meta_Control_asciicircum {7 46} Meta_Control_asciicircum {7 47} Meta_Control_asciicircum {7 48} six {7 49} asciicircum {7 50} six {7 51} asciicircum {7 52} Control_asciicircum {7 53} Control_asciicircum {7 54} Control_asciicircum {7 55} Control_asciicircum {7 56} Meta_six {7 57} Meta_asciicircum {7 58} Meta_six {7 59} Meta_asciicircum {7 60} Meta_Control_asciicircum {7 61} Meta_Control_asciicircum {7 62} Meta_Control_asciicircum {7 63} Meta_Control_asciicircum {7 64} six {7 65} asciicircum {7 66} six {7 67} asciicircum {7 68} Control_asciicircum {7 69} Control_asciicircum {7 70} Control_asciicircum {7 71} Control_asciicircum {7 72} Meta_six {7 73} Meta_asciicircum {7 74} Meta_six {7 75} Meta_asciicircum {7 76} Meta_Control_asciicircum {7 77} Meta_Control_asciicircum {7 78} Meta_Control_asciicircum {7 79} Meta_Control_asciicircum {7 80} six {7 81} asciicircum {7 82} six {7 83} asciicircum {7 84} Control_asciicircum {7 85} Control_asciicircum {7 86} Control_asciicircum {7 87} Control_asciicircum {7 88} Meta_six {7 89} Meta_asciicircum {7 90} Meta_six {7 91} Meta_asciicircum {7 92} Meta_Control_asciicircum {7 93} Meta_Control_asciicircum {7 94} Meta_Control_asciicircum {7 95} Meta_Control_asciicircum {7 96} six {7 97} asciicircum {7 98} six {7 99} asciicircum {7 100} Control_asciicircum {7 101} Control_asciicircum {7 102} Control_asciicircum {7 103} Control_asciicircum {7 104} Meta_six {7 105} Meta_asciicircum {7 106} Meta_six {7 107} Meta_asciicircum {7 108} Meta_Control_asciicircum {7 109} Meta_Control_asciicircum {7 110} Meta_Control_asciicircum {7 111} Meta_Control_asciicircum {7 112} six {7 113} asciicircum {7 114} six {7 115} asciicircum {7 116} Control_asciicircum {7 117} Control_asciicircum {7 118} Control_asciicircum {7 119} Control_asciicircum {7 120} Meta_six {7 121} Meta_asciicircum {7 122} Meta_six {7 123} Meta_asciicircum {7 124} Meta_Control_asciicircum {7 125} Meta_Control_asciicircum {7 126} Meta_Control_asciicircum {7 127} Meta_Control_asciicircum {8 0} seven {8 1} ampersand {8 2} seven {8 3} ampersand {8 4} seven {8 5} ampersand {8 6} seven {8 7} ampersand {8 8} Meta_seven {8 9} Meta_ampersand {8 10} Meta_seven {8 11} Meta_ampersand {8 12} Meta_seven {8 13} Meta_ampersand {8 14} Meta_seven {8 15} Meta_ampersand {8 16} seven {8 17} ampersand {8 18} seven {8 19} ampersand {8 20} seven {8 21} ampersand {8 22} seven {8 23} ampersand {8 24} Meta_seven {8 25} Meta_ampersand {8 26} Meta_seven {8 27} Meta_ampersand {8 28} Meta_seven {8 29} Meta_ampersand {8 30} Meta_seven {8 31} Meta_ampersand {8 32} seven {8 33} ampersand {8 34} seven {8 35} ampersand {8 36} seven {8 37} ampersand {8 38} seven {8 39} ampersand {8 40} Meta_seven {8 41} Meta_ampersand {8 42} Meta_seven {8 43} Meta_ampersand {8 44} Meta_seven {8 45} Meta_ampersand {8 46} Meta_seven {8 47} Meta_ampersand {8 48} seven {8 49} ampersand {8 50} seven {8 51} ampersand {8 52} seven {8 53} ampersand {8 54} seven {8 55} ampersand {8 56} Meta_seven {8 57} Meta_ampersand {8 58} Meta_seven {8 59} Meta_ampersand {8 60} Meta_seven {8 61} Meta_ampersand {8 62} Meta_seven {8 63} Meta_ampersand {8 64} seven {8 65} ampersand {8 66} seven {8 67} ampersand {8 68} seven {8 69} ampersand {8 70} seven {8 71} ampersand {8 72} Meta_seven {8 73} Meta_ampersand {8 74} Meta_seven {8 75} Meta_ampersand {8 76} Meta_seven {8 77} Meta_ampersand {8 78} Meta_seven {8 79} Meta_ampersand {8 80} seven {8 81} ampersand {8 82} seven {8 83} ampersand {8 84} seven {8 85} ampersand {8 86} seven {8 87} ampersand {8 88} Meta_seven {8 89} Meta_ampersand {8 90} Meta_seven {8 91} Meta_ampersand {8 92} Meta_seven {8 93} Meta_ampersand {8 94} Meta_seven {8 95} Meta_ampersand {8 96} seven {8 97} ampersand {8 98} seven {8 99} ampersand {8 100} seven {8 101} ampersand {8 102} seven {8 103} ampersand {8 104} Meta_seven {8 105} Meta_ampersand {8 106} Meta_seven {8 107} Meta_ampersand {8 108} Meta_seven {8 109} Meta_ampersand {8 110} Meta_seven {8 111} Meta_ampersand {8 112} seven {8 113} ampersand {8 114} seven {8 115} ampersand {8 116} seven {8 117} ampersand {8 118} seven {8 119} ampersand {8 120} Meta_seven {8 121} Meta_ampersand {8 122} Meta_seven {8 123} Meta_ampersand {8 124} Meta_seven {8 125} Meta_ampersand {8 126} Meta_seven {8 127} Meta_ampersand {9 0} eight {9 1} asterisk {9 2} eight {9 3} asterisk {9 4} eight {9 5} asterisk {9 6} eight {9 7} asterisk {9 8} Meta_eight {9 9} Meta_asterisk {9 10} Meta_eight {9 11} Meta_asterisk {9 12} Meta_eight {9 13} Meta_asterisk {9 14} Meta_eight {9 15} Meta_asterisk {9 16} eight {9 17} asterisk {9 18} eight {9 19} asterisk {9 20} eight {9 21} asterisk {9 22} eight {9 23} asterisk {9 24} Meta_eight {9 25} Meta_asterisk {9 26} Meta_eight {9 27} Meta_asterisk {9 28} Meta_eight {9 29} Meta_asterisk {9 30} Meta_eight {9 31} Meta_asterisk {9 32} eight {9 33} asterisk {9 34} eight {9 35} asterisk {9 36} eight {9 37} asterisk {9 38} eight {9 39} asterisk {9 40} Meta_eight {9 41} Meta_asterisk {9 42} Meta_eight {9 43} Meta_asterisk {9 44} Meta_eight {9 45} Meta_asterisk {9 46} Meta_eight {9 47} Meta_asterisk {9 48} eight {9 49} asterisk {9 50} eight {9 51} asterisk {9 52} eight {9 53} asterisk {9 54} eight {9 55} asterisk {9 56} Meta_eight {9 57} Meta_asterisk {9 58} Meta_eight {9 59} Meta_asterisk {9 60} Meta_eight {9 61} Meta_asterisk {9 62} Meta_eight {9 63} Meta_asterisk {9 64} eight {9 65} asterisk {9 66} eight {9 67} asterisk {9 68} eight {9 69} asterisk {9 70} eight {9 71} asterisk {9 72} Meta_eight {9 73} Meta_asterisk {9 74} Meta_eight {9 75} Meta_asterisk {9 76} Meta_eight {9 77} Meta_asterisk {9 78} Meta_eight {9 79} Meta_asterisk {9 80} eight {9 81} asterisk {9 82} eight {9 83} asterisk {9 84} eight {9 85} asterisk {9 86} eight {9 87} asterisk {9 88} Meta_eight {9 89} Meta_asterisk {9 90} Meta_eight {9 91} Meta_asterisk {9 92} Meta_eight {9 93} Meta_asterisk {9 94} Meta_eight {9 95} Meta_asterisk {9 96} eight {9 97} asterisk {9 98} eight {9 99} asterisk {9 100} eight {9 101} asterisk {9 102} eight {9 103} asterisk {9 104} Meta_eight {9 105} Meta_asterisk {9 106} Meta_eight {9 107} Meta_asterisk {9 108} Meta_eight {9 109} Meta_asterisk {9 110} Meta_eight {9 111} Meta_asterisk {9 112} eight {9 113} asterisk {9 114} eight {9 115} asterisk {9 116} eight {9 117} asterisk {9 118} eight {9 119} asterisk {9 120} Meta_eight {9 121} Meta_asterisk {9 122} Meta_eight {9 123} Meta_asterisk {9 124} Meta_eight {9 125} Meta_asterisk {9 126} Meta_eight {9 127} Meta_asterisk {10 0} nine {10 1} parenleft {10 2} nine {10 3} parenleft {10 4} nine {10 5} parenleft {10 6} nine {10 7} parenleft {10 8} Meta_nine {10 9} Meta_parenleft {10 10} Meta_nine {10 11} Meta_parenleft {10 12} Meta_nine {10 13} Meta_parenleft {10 14} Meta_nine {10 15} Meta_parenleft {10 16} nine {10 17} parenleft {10 18} nine {10 19} parenleft {10 20} nine {10 21} parenleft {10 22} nine {10 23} parenleft {10 24} Meta_nine {10 25} Meta_parenleft {10 26} Meta_nine {10 27} Meta_parenleft {10 28} Meta_nine {10 29} Meta_parenleft {10 30} Meta_nine {10 31} Meta_parenleft {10 32} nine {10 33} parenleft {10 34} nine {10 35} parenleft {10 36} nine {10 37} parenleft {10 38} nine {10 39} parenleft {10 40} Meta_nine {10 41} Meta_parenleft {10 42} Meta_nine {10 43} Meta_parenleft {10 44} Meta_nine {10 45} Meta_parenleft {10 46} Meta_nine {10 47} Meta_parenleft {10 48} nine {10 49} parenleft {10 50} nine {10 51} parenleft {10 52} nine {10 53} parenleft {10 54} nine {10 55} parenleft {10 56} Meta_nine {10 57} Meta_parenleft {10 58} Meta_nine {10 59} Meta_parenleft {10 60} Meta_nine {10 61} Meta_parenleft {10 62} Meta_nine {10 63} Meta_parenleft {10 64} nine {10 65} parenleft {10 66} nine {10 67} parenleft {10 68} nine {10 69} parenleft {10 70} nine {10 71} parenleft {10 72} Meta_nine {10 73} Meta_parenleft {10 74} Meta_nine {10 75} Meta_parenleft {10 76} Meta_nine {10 77} Meta_parenleft {10 78} Meta_nine {10 79} Meta_parenleft {10 80} nine {10 81} parenleft {10 82} nine {10 83} parenleft {10 84} nine {10 85} parenleft {10 86} nine {10 87} parenleft {10 88} Meta_nine {10 89} Meta_parenleft {10 90} Meta_nine {10 91} Meta_parenleft {10 92} Meta_nine {10 93} Meta_parenleft {10 94} Meta_nine {10 95} Meta_parenleft {10 96} nine {10 97} parenleft {10 98} nine {10 99} parenleft {10 100} nine {10 101} parenleft {10 102} nine {10 103} parenleft {10 104} Meta_nine {10 105} Meta_parenleft {10 106} Meta_nine {10 107} Meta_parenleft {10 108} Meta_nine {10 109} Meta_parenleft {10 110} Meta_nine {10 111} Meta_parenleft {10 112} nine {10 113} parenleft {10 114} nine {10 115} parenleft {10 116} nine {10 117} parenleft {10 118} nine {10 119} parenleft {10 120} Meta_nine {10 121} Meta_parenleft {10 122} Meta_nine {10 123} Meta_parenleft {10 124} Meta_nine {10 125} Meta_parenleft {10 126} Meta_nine {10 127} Meta_parenleft {11 0} zero {11 1} parenright {11 2} zero {11 3} parenright {11 4} zero {11 5} parenright {11 6} zero {11 7} parenright {11 8} Meta_zero {11 9} Meta_parenright {11 10} Meta_zero {11 11} Meta_parenright {11 12} Meta_zero {11 13} Meta_parenright {11 14} Meta_zero {11 15} Meta_parenright {11 16} zero {11 17} parenright {11 18} zero {11 19} parenright {11 20} zero {11 21} parenright {11 22} zero {11 23} parenright {11 24} Meta_zero {11 25} Meta_parenright {11 26} Meta_zero {11 27} Meta_parenright {11 28} Meta_zero {11 29} Meta_parenright {11 30} Meta_zero {11 31} Meta_parenright {11 32} zero {11 33} parenright {11 34} zero {11 35} parenright {11 36} zero {11 37} parenright {11 38} zero {11 39} parenright {11 40} Meta_zero {11 41} Meta_parenright {11 42} Meta_zero {11 43} Meta_parenright {11 44} Meta_zero {11 45} Meta_parenright {11 46} Meta_zero {11 47} Meta_parenright {11 48} zero {11 49} parenright {11 50} zero {11 51} parenright {11 52} zero {11 53} parenright {11 54} zero {11 55} parenright {11 56} Meta_zero {11 57} Meta_parenright {11 58} Meta_zero {11 59} Meta_parenright {11 60} Meta_zero {11 61} Meta_parenright {11 62} Meta_zero {11 63} Meta_parenright {11 64} zero {11 65} parenright {11 66} zero {11 67} parenright {11 68} zero {11 69} parenright {11 70} zero {11 71} parenright {11 72} Meta_zero {11 73} Meta_parenright {11 74} Meta_zero {11 75} Meta_parenright {11 76} Meta_zero {11 77} Meta_parenright {11 78} Meta_zero {11 79} Meta_parenright {11 80} zero {11 81} parenright {11 82} zero {11 83} parenright {11 84} zero {11 85} parenright {11 86} zero {11 87} parenright {11 88} Meta_zero {11 89} Meta_parenright {11 90} Meta_zero {11 91} Meta_parenright {11 92} Meta_zero {11 93} Meta_parenright {11 94} Meta_zero {11 95} Meta_parenright {11 96} zero {11 97} parenright {11 98} zero {11 99} parenright {11 100} zero {11 101} parenright {11 102} zero {11 103} parenright {11 104} Meta_zero {11 105} Meta_parenright {11 106} Meta_zero {11 107} Meta_parenright {11 108} Meta_zero {11 109} Meta_parenright {11 110} Meta_zero {11 111} Meta_parenright {11 112} zero {11 113} parenright {11 114} zero {11 115} parenright {11 116} zero {11 117} parenright {11 118} zero {11 119} parenright {11 120} Meta_zero {11 121} Meta_parenright {11 122} Meta_zero {11 123} Meta_parenright {11 124} Meta_zero {11 125} Meta_parenright {11 126} Meta_zero {11 127} Meta_parenright {12 0} minus {12 1} underscore {12 2} minus {12 3} underscore {12 4} Control_underscore {12 5} Control_underscore {12 6} Control_underscore {12 7} Control_underscore {12 8} Meta_minus {12 9} Meta_underscore {12 10} Meta_minus {12 11} Meta_underscore {12 12} Meta_Control_underscore {12 13} Meta_Control_underscore {12 14} Meta_Control_underscore {12 15} Meta_Control_underscore {12 16} minus {12 17} underscore {12 18} minus {12 19} underscore {12 20} Control_underscore {12 21} Control_underscore {12 22} Control_underscore {12 23} Control_underscore {12 24} Meta_minus {12 25} Meta_underscore {12 26} Meta_minus {12 27} Meta_underscore {12 28} Meta_Control_underscore {12 29} Meta_Control_underscore {12 30} Meta_Control_underscore {12 31} Meta_Control_underscore {12 32} minus {12 33} underscore {12 34} minus {12 35} underscore {12 36} Control_underscore {12 37} Control_underscore {12 38} Control_underscore {12 39} Control_underscore {12 40} Meta_minus {12 41} Meta_underscore {12 42} Meta_minus {12 43} Meta_underscore {12 44} Meta_Control_underscore {12 45} Meta_Control_underscore {12 46} Meta_Control_underscore {12 47} Meta_Control_underscore {12 48} minus {12 49} underscore {12 50} minus {12 51} underscore {12 52} Control_underscore {12 53} Control_underscore {12 54} Control_underscore {12 55} Control_underscore {12 56} Meta_minus {12 57} Meta_underscore {12 58} Meta_minus {12 59} Meta_underscore {12 60} Meta_Control_underscore {12 61} Meta_Control_underscore {12 62} Meta_Control_underscore {12 63} Meta_Control_underscore {12 64} minus {12 65} underscore {12 66} minus {12 67} underscore {12 68} Control_underscore {12 69} Control_underscore {12 70} Control_underscore {12 71} Control_underscore {12 72} Meta_minus {12 73} Meta_underscore {12 74} Meta_minus {12 75} Meta_underscore {12 76} Meta_Control_underscore {12 77} Meta_Control_underscore {12 78} Meta_Control_underscore {12 79} Meta_Control_underscore {12 80} minus {12 81} underscore {12 82} minus {12 83} underscore {12 84} Control_underscore {12 85} Control_underscore {12 86} Control_underscore {12 87} Control_underscore {12 88} Meta_minus {12 89} Meta_underscore {12 90} Meta_minus {12 91} Meta_underscore {12 92} Meta_Control_underscore {12 93} Meta_Control_underscore {12 94} Meta_Control_underscore {12 95} Meta_Control_underscore {12 96} minus {12 97} underscore {12 98} minus {12 99} underscore {12 100} Control_underscore {12 101} Control_underscore {12 102} Control_underscore {12 103} Control_underscore {12 104} Meta_minus {12 105} Meta_underscore {12 106} Meta_minus {12 107} Meta_underscore {12 108} Meta_Control_underscore {12 109} Meta_Control_underscore {12 110} Meta_Control_underscore {12 111} Meta_Control_underscore {12 112} minus {12 113} underscore {12 114} minus {12 115} underscore {12 116} Control_underscore {12 117} Control_underscore {12 118} Control_underscore {12 119} Control_underscore {12 120} Meta_minus {12 121} Meta_underscore {12 122} Meta_minus {12 123} Meta_underscore {12 124} Meta_Control_underscore {12 125} Meta_Control_underscore {12 126} Meta_Control_underscore {12 127} Meta_Control_underscore {13 0} equal {13 1} plus {13 2} equal {13 3} plus {13 4} equal {13 5} plus {13 6} equal {13 7} plus {13 8} Meta_equal {13 9} Meta_plus {13 10} Meta_equal {13 11} Meta_plus {13 12} Meta_equal {13 13} Meta_plus {13 14} Meta_equal {13 15} Meta_plus {13 16} equal {13 17} plus {13 18} equal {13 19} plus {13 20} equal {13 21} plus {13 22} equal {13 23} plus {13 24} Meta_equal {13 25} Meta_plus {13 26} Meta_equal {13 27} Meta_plus {13 28} Meta_equal {13 29} Meta_plus {13 30} Meta_equal {13 31} Meta_plus {13 32} equal {13 33} plus {13 34} equal {13 35} plus {13 36} equal {13 37} plus {13 38} equal {13 39} plus {13 40} Meta_equal {13 41} Meta_plus {13 42} Meta_equal {13 43} Meta_plus {13 44} Meta_equal {13 45} Meta_plus {13 46} Meta_equal {13 47} Meta_plus {13 48} equal {13 49} plus {13 50} equal {13 51} plus {13 52} equal {13 53} plus {13 54} equal {13 55} plus {13 56} Meta_equal {13 57} Meta_plus {13 58} Meta_equal {13 59} Meta_plus {13 60} Meta_equal {13 61} Meta_plus {13 62} Meta_equal {13 63} Meta_plus {13 64} equal {13 65} plus {13 66} equal {13 67} plus {13 68} equal {13 69} plus {13 70} equal {13 71} plus {13 72} Meta_equal {13 73} Meta_plus {13 74} Meta_equal {13 75} Meta_plus {13 76} Meta_equal {13 77} Meta_plus {13 78} Meta_equal {13 79} Meta_plus {13 80} equal {13 81} plus {13 82} equal {13 83} plus {13 84} equal {13 85} plus {13 86} equal {13 87} plus {13 88} Meta_equal {13 89} Meta_plus {13 90} Meta_equal {13 91} Meta_plus {13 92} Meta_equal {13 93} Meta_plus {13 94} Meta_equal {13 95} Meta_plus {13 96} equal {13 97} plus {13 98} equal {13 99} plus {13 100} equal {13 101} plus {13 102} equal {13 103} plus {13 104} Meta_equal {13 105} Meta_plus {13 106} Meta_equal {13 107} Meta_plus {13 108} Meta_equal {13 109} Meta_plus {13 110} Meta_equal {13 111} Meta_plus {13 112} equal {13 113} plus {13 114} equal {13 115} plus {13 116} equal {13 117} plus {13 118} equal {13 119} plus {13 120} Meta_equal {13 121} Meta_plus {13 122} Meta_equal {13 123} Meta_plus {13 124} Meta_equal {13 125} Meta_plus {13 126} Meta_equal {13 127} Meta_plus {14 0} Delete {14 1} Delete {14 2} Delete {14 3} Delete {14 4} BackSpace {14 5} BackSpace {14 6} BackSpace {14 7} BackSpace {14 8} Meta_Delete {14 9} Meta_Delete {14 10} Meta_Delete {14 11} Meta_Delete {14 12} Meta_BackSpace {14 13} Meta_BackSpace {14 14} Meta_BackSpace {14 15} Meta_BackSpace {14 16} Delete {14 17} Delete {14 18} Delete {14 19} Delete {14 20} BackSpace {14 21} BackSpace {14 22} BackSpace {14 23} BackSpace {14 24} Meta_Delete {14 25} Meta_Delete {14 26} Meta_Delete {14 27} Meta_Delete {14 28} Meta_BackSpace {14 29} Meta_BackSpace {14 30} Meta_BackSpace {14 31} Meta_BackSpace {14 32} Delete {14 33} Delete {14 34} Delete {14 35} Delete {14 36} BackSpace {14 37} BackSpace {14 38} BackSpace {14 39} BackSpace {14 40} Meta_Delete {14 41} Meta_Delete {14 42} Meta_Delete {14 43} Meta_Delete {14 44} Meta_BackSpace {14 45} Meta_BackSpace {14 46} Meta_BackSpace {14 47} Meta_BackSpace {14 48} Delete {14 49} Delete {14 50} Delete {14 51} Delete {14 52} BackSpace {14 53} BackSpace {14 54} BackSpace {14 55} BackSpace {14 56} Meta_Delete {14 57} Meta_Delete {14 58} Meta_Delete {14 59} Meta_Delete {14 60} Meta_BackSpace {14 61} Meta_BackSpace {14 62} Meta_BackSpace {14 63} Meta_BackSpace {14 64} Delete {14 65} Delete {14 66} Delete {14 67} Delete {14 68} BackSpace {14 69} BackSpace {14 70} BackSpace {14 71} BackSpace {14 72} Meta_Delete {14 73} Meta_Delete {14 74} Meta_Delete {14 75} Meta_Delete {14 76} Meta_BackSpace {14 77} Meta_BackSpace {14 78} Meta_BackSpace {14 79} Meta_BackSpace {14 80} Delete {14 81} Delete {14 82} Delete {14 83} Delete {14 84} BackSpace {14 85} BackSpace {14 86} BackSpace {14 87} BackSpace {14 88} Meta_Delete {14 89} Meta_Delete {14 90} Meta_Delete {14 91} Meta_Delete {14 92} Meta_BackSpace {14 93} Meta_BackSpace {14 94} Meta_BackSpace {14 95} Meta_BackSpace {14 96} Delete {14 97} Delete {14 98} Delete {14 99} Delete {14 100} BackSpace {14 101} BackSpace {14 102} BackSpace {14 103} BackSpace {14 104} Meta_Delete {14 105} Meta_Delete {14 106} Meta_Delete {14 107} Meta_Delete {14 108} Meta_BackSpace {14 109} Meta_BackSpace {14 110} Meta_BackSpace {14 111} Meta_BackSpace {14 112} Delete {14 113} Delete {14 114} Delete {14 115} Delete {14 116} BackSpace {14 117} BackSpace {14 118} BackSpace {14 119} BackSpace {14 120} Meta_Delete {14 121} Meta_Delete {14 122} Meta_Delete {14 123} Meta_Delete {14 124} Meta_BackSpace {14 125} Meta_BackSpace {14 126} Meta_BackSpace {14 127} Meta_BackSpace {15 0} Tab {15 1} Meta_Tab {15 2} Tab {15 3} Meta_Tab {15 4} Tab {15 5} Tab {15 6} Tab {15 7} Tab {15 8} Meta_Tab {15 9} Meta_Tab {15 10} Meta_Tab {15 11} Meta_Tab {15 12} Meta_Tab {15 13} Meta_Tab {15 14} Meta_Tab {15 15} Meta_Tab {15 16} Tab {15 17} Meta_Tab {15 18} Tab {15 19} Meta_Tab {15 20} Tab {15 21} Tab {15 22} Tab {15 23} Tab {15 24} Meta_Tab {15 25} Meta_Tab {15 26} Meta_Tab {15 27} Meta_Tab {15 28} Meta_Tab {15 29} Meta_Tab {15 30} Meta_Tab {15 31} Meta_Tab {15 32} Tab {15 33} Meta_Tab {15 34} Tab {15 35} Meta_Tab {15 36} Tab {15 37} Tab {15 38} Tab {15 39} Tab {15 40} Meta_Tab {15 41} Meta_Tab {15 42} Meta_Tab {15 43} Meta_Tab {15 44} Meta_Tab {15 45} Meta_Tab {15 46} Meta_Tab {15 47} Meta_Tab {15 48} Tab {15 49} Meta_Tab {15 50} Tab {15 51} Meta_Tab {15 52} Tab {15 53} Tab {15 54} Tab {15 55} Tab {15 56} Meta_Tab {15 57} Meta_Tab {15 58} Meta_Tab {15 59} Meta_Tab {15 60} Meta_Tab {15 61} Meta_Tab {15 62} Meta_Tab {15 63} Meta_Tab {15 64} Tab {15 65} Meta_Tab {15 66} Tab {15 67} Meta_Tab {15 68} Tab {15 69} Tab {15 70} Tab {15 71} Tab {15 72} Meta_Tab {15 73} Meta_Tab {15 74} Meta_Tab {15 75} Meta_Tab {15 76} Meta_Tab {15 77} Meta_Tab {15 78} Meta_Tab {15 79} Meta_Tab {15 80} Tab {15 81} Meta_Tab {15 82} Tab {15 83} Meta_Tab {15 84} Tab {15 85} Tab {15 86} Tab {15 87} Tab {15 88} Meta_Tab {15 89} Meta_Tab {15 90} Meta_Tab {15 91} Meta_Tab {15 92} Meta_Tab {15 93} Meta_Tab {15 94} Meta_Tab {15 95} Meta_Tab {15 96} Tab {15 97} Meta_Tab {15 98} Tab {15 99} Meta_Tab {15 100} Tab {15 101} Tab {15 102} Tab {15 103} Tab {15 104} Meta_Tab {15 105} Meta_Tab {15 106} Meta_Tab {15 107} Meta_Tab {15 108} Meta_Tab {15 109} Meta_Tab {15 110} Meta_Tab {15 111} Meta_Tab {15 112} Tab {15 113} Meta_Tab {15 114} Tab {15 115} Meta_Tab {15 116} Tab {15 117} Tab {15 118} Tab {15 119} Tab {15 120} Meta_Tab {15 121} Meta_Tab {15 122} Meta_Tab {15 123} Meta_Tab {15 124} Meta_Tab {15 125} Meta_Tab {15 126} Meta_Tab {15 127} Meta_Tab {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} Control_q {16 5} Control_q {16 6} Control_q {16 7} Control_q {16 8} Meta_q {16 9} Meta_Q {16 10} Meta_q {16 11} Meta_Q {16 12} Meta_Control_q {16 13} Meta_Control_q {16 14} Meta_Control_q {16 15} Meta_Control_q {16 16} q {16 17} Q {16 18} q {16 19} Q {16 20} Control_q {16 21} Control_q {16 22} Control_q {16 23} Control_q {16 24} Meta_q {16 25} Meta_Q {16 26} Meta_q {16 27} Meta_Q {16 28} Meta_Control_q {16 29} Meta_Control_q {16 30} Meta_Control_q {16 31} Meta_Control_q {16 32} q {16 33} Q {16 34} q {16 35} Q {16 36} Control_q {16 37} Control_q {16 38} Control_q {16 39} Control_q {16 40} Meta_q {16 41} Meta_Q {16 42} Meta_q {16 43} Meta_Q {16 44} Meta_Control_q {16 45} Meta_Control_q {16 46} Meta_Control_q {16 47} Meta_Control_q {16 48} q {16 49} Q {16 50} q {16 51} Q {16 52} Control_q {16 53} Control_q {16 54} Control_q {16 55} Control_q {16 56} Meta_q {16 57} Meta_Q {16 58} Meta_q {16 59} Meta_Q {16 60} Meta_Control_q {16 61} Meta_Control_q {16 62} Meta_Control_q {16 63} Meta_Control_q {16 64} Q {16 65} q {16 66} Q {16 67} q {16 68} Control_q {16 69} Control_q {16 70} Control_q {16 71} Control_q {16 72} Meta_q {16 73} Meta_Q {16 74} Meta_q {16 75} Meta_Q {16 76} Meta_Control_q {16 77} Meta_Control_q {16 78} Meta_Control_q {16 79} Meta_Control_q {16 80} Q {16 81} q {16 82} Q {16 83} q {16 84} Control_q {16 85} Control_q {16 86} Control_q {16 87} Control_q {16 88} Meta_q {16 89} Meta_Q {16 90} Meta_q {16 91} Meta_Q {16 92} Meta_Control_q {16 93} Meta_Control_q {16 94} Meta_Control_q {16 95} Meta_Control_q {16 96} Q {16 97} q {16 98} Q {16 99} q {16 100} Control_q {16 101} Control_q {16 102} Control_q {16 103} Control_q {16 104} Meta_q {16 105} Meta_Q {16 106} Meta_q {16 107} Meta_Q {16 108} Meta_Control_q {16 109} Meta_Control_q {16 110} Meta_Control_q {16 111} Meta_Control_q {16 112} Q {16 113} q {16 114} Q {16 115} q {16 116} Control_q {16 117} Control_q {16 118} Control_q {16 119} Control_q {16 120} Meta_q {16 121} Meta_Q {16 122} Meta_q {16 123} Meta_Q {16 124} Meta_Control_q {16 125} Meta_Control_q {16 126} Meta_Control_q {16 127} Meta_Control_q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} Control_w {17 5} Control_w {17 6} Control_w {17 7} Control_w {17 8} Meta_w {17 9} Meta_W {17 10} Meta_w {17 11} Meta_W {17 12} Meta_Control_w {17 13} Meta_Control_w {17 14} Meta_Control_w {17 15} Meta_Control_w {17 16} w {17 17} W {17 18} w {17 19} W {17 20} Control_w {17 21} Control_w {17 22} Control_w {17 23} Control_w {17 24} Meta_w {17 25} Meta_W {17 26} Meta_w {17 27} Meta_W {17 28} Meta_Control_w {17 29} Meta_Control_w {17 30} Meta_Control_w {17 31} Meta_Control_w {17 32} w {17 33} W {17 34} w {17 35} W {17 36} Control_w {17 37} Control_w {17 38} Control_w {17 39} Control_w {17 40} Meta_w {17 41} Meta_W {17 42} Meta_w {17 43} Meta_W {17 44} Meta_Control_w {17 45} Meta_Control_w {17 46} Meta_Control_w {17 47} Meta_Control_w {17 48} w {17 49} W {17 50} w {17 51} W {17 52} Control_w {17 53} Control_w {17 54} Control_w {17 55} Control_w {17 56} Meta_w {17 57} Meta_W {17 58} Meta_w {17 59} Meta_W {17 60} Meta_Control_w {17 61} Meta_Control_w {17 62} Meta_Control_w {17 63} Meta_Control_w {17 64} W {17 65} w {17 66} W {17 67} w {17 68} Control_w {17 69} Control_w {17 70} Control_w {17 71} Control_w {17 72} Meta_w {17 73} Meta_W {17 74} Meta_w {17 75} Meta_W {17 76} Meta_Control_w {17 77} Meta_Control_w {17 78} Meta_Control_w {17 79} Meta_Control_w {17 80} W {17 81} w {17 82} W {17 83} w {17 84} Control_w {17 85} Control_w {17 86} Control_w {17 87} Control_w {17 88} Meta_w {17 89} Meta_W {17 90} Meta_w {17 91} Meta_W {17 92} Meta_Control_w {17 93} Meta_Control_w {17 94} Meta_Control_w {17 95} Meta_Control_w {17 96} W {17 97} w {17 98} W {17 99} w {17 100} Control_w {17 101} Control_w {17 102} Control_w {17 103} Control_w {17 104} Meta_w {17 105} Meta_W {17 106} Meta_w {17 107} Meta_W {17 108} Meta_Control_w {17 109} Meta_Control_w {17 110} Meta_Control_w {17 111} Meta_Control_w {17 112} W {17 113} w {17 114} W {17 115} w {17 116} Control_w {17 117} Control_w {17 118} Control_w {17 119} Control_w {17 120} Meta_w {17 121} Meta_W {17 122} Meta_w {17 123} Meta_W {17 124} Meta_Control_w {17 125} Meta_Control_w {17 126} Meta_Control_w {17 127} Meta_Control_w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} Control_e {18 5} Control_e {18 6} Control_e {18 7} Control_e {18 8} Meta_e {18 9} Meta_E {18 10} Meta_e {18 11} Meta_E {18 12} Meta_Control_e {18 13} Meta_Control_e {18 14} Meta_Control_e {18 15} Meta_Control_e {18 16} e {18 17} E {18 18} e {18 19} E {18 20} Control_e {18 21} Control_e {18 22} Control_e {18 23} Control_e {18 24} Meta_e {18 25} Meta_E {18 26} Meta_e {18 27} Meta_E {18 28} Meta_Control_e {18 29} Meta_Control_e {18 30} Meta_Control_e {18 31} Meta_Control_e {18 32} e {18 33} E {18 34} e {18 35} E {18 36} Control_e {18 37} Control_e {18 38} Control_e {18 39} Control_e {18 40} Meta_e {18 41} Meta_E {18 42} Meta_e {18 43} Meta_E {18 44} Meta_Control_e {18 45} Meta_Control_e {18 46} Meta_Control_e {18 47} Meta_Control_e {18 48} e {18 49} E {18 50} e {18 51} E {18 52} Control_e {18 53} Control_e {18 54} Control_e {18 55} Control_e {18 56} Meta_e {18 57} Meta_E {18 58} Meta_e {18 59} Meta_E {18 60} Meta_Control_e {18 61} Meta_Control_e {18 62} Meta_Control_e {18 63} Meta_Control_e {18 64} E {18 65} e {18 66} E {18 67} e {18 68} Control_e {18 69} Control_e {18 70} Control_e {18 71} Control_e {18 72} Meta_e {18 73} Meta_E {18 74} Meta_e {18 75} Meta_E {18 76} Meta_Control_e {18 77} Meta_Control_e {18 78} Meta_Control_e {18 79} Meta_Control_e {18 80} E {18 81} e {18 82} E {18 83} e {18 84} Control_e {18 85} Control_e {18 86} Control_e {18 87} Control_e {18 88} Meta_e {18 89} Meta_E {18 90} Meta_e {18 91} Meta_E {18 92} Meta_Control_e {18 93} Meta_Control_e {18 94} Meta_Control_e {18 95} Meta_Control_e {18 96} E {18 97} e {18 98} E {18 99} e {18 100} Control_e {18 101} Control_e {18 102} Control_e {18 103} Control_e {18 104} Meta_e {18 105} Meta_E {18 106} Meta_e {18 107} Meta_E {18 108} Meta_Control_e {18 109} Meta_Control_e {18 110} Meta_Control_e {18 111} Meta_Control_e {18 112} E {18 113} e {18 114} E {18 115} e {18 116} Control_e {18 117} Control_e {18 118} Control_e {18 119} Control_e {18 120} Meta_e {18 121} Meta_E {18 122} Meta_e {18 123} Meta_E {18 124} Meta_Control_e {18 125} Meta_Control_e {18 126} Meta_Control_e {18 127} Meta_Control_e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} Control_r {19 5} Control_r {19 6} Control_r {19 7} Control_r {19 8} Meta_r {19 9} Meta_R {19 10} Meta_r {19 11} Meta_R {19 12} Meta_Control_r {19 13} Meta_Control_r {19 14} Meta_Control_r {19 15} Meta_Control_r {19 16} r {19 17} R {19 18} r {19 19} R {19 20} Control_r {19 21} Control_r {19 22} Control_r {19 23} Control_r {19 24} Meta_r {19 25} Meta_R {19 26} Meta_r {19 27} Meta_R {19 28} Meta_Control_r {19 29} Meta_Control_r {19 30} Meta_Control_r {19 31} Meta_Control_r {19 32} r {19 33} R {19 34} r {19 35} R {19 36} Control_r {19 37} Control_r {19 38} Control_r {19 39} Control_r {19 40} Meta_r {19 41} Meta_R {19 42} Meta_r {19 43} Meta_R {19 44} Meta_Control_r {19 45} Meta_Control_r {19 46} Meta_Control_r {19 47} Meta_Control_r {19 48} r {19 49} R {19 50} r {19 51} R {19 52} Control_r {19 53} Control_r {19 54} Control_r {19 55} Control_r {19 56} Meta_r {19 57} Meta_R {19 58} Meta_r {19 59} Meta_R {19 60} Meta_Control_r {19 61} Meta_Control_r {19 62} Meta_Control_r {19 63} Meta_Control_r {19 64} R {19 65} r {19 66} R {19 67} r {19 68} Control_r {19 69} Control_r {19 70} Control_r {19 71} Control_r {19 72} Meta_r {19 73} Meta_R {19 74} Meta_r {19 75} Meta_R {19 76} Meta_Control_r {19 77} Meta_Control_r {19 78} Meta_Control_r {19 79} Meta_Control_r {19 80} R {19 81} r {19 82} R {19 83} r {19 84} Control_r {19 85} Control_r {19 86} Control_r {19 87} Control_r {19 88} Meta_r {19 89} Meta_R {19 90} Meta_r {19 91} Meta_R {19 92} Meta_Control_r {19 93} Meta_Control_r {19 94} Meta_Control_r {19 95} Meta_Control_r {19 96} R {19 97} r {19 98} R {19 99} r {19 100} Control_r {19 101} Control_r {19 102} Control_r {19 103} Control_r {19 104} Meta_r {19 105} Meta_R {19 106} Meta_r {19 107} Meta_R {19 108} Meta_Control_r {19 109} Meta_Control_r {19 110} Meta_Control_r {19 111} Meta_Control_r {19 112} R {19 113} r {19 114} R {19 115} r {19 116} Control_r {19 117} Control_r {19 118} Control_r {19 119} Control_r {19 120} Meta_r {19 121} Meta_R {19 122} Meta_r {19 123} Meta_R {19 124} Meta_Control_r {19 125} Meta_Control_r {19 126} Meta_Control_r {19 127} Meta_Control_r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} Control_t {20 5} Control_t {20 6} Control_t {20 7} Control_t {20 8} Meta_t {20 9} Meta_T {20 10} Meta_t {20 11} Meta_T {20 12} Meta_Control_t {20 13} Meta_Control_t {20 14} Meta_Control_t {20 15} Meta_Control_t {20 16} t {20 17} T {20 18} t {20 19} T {20 20} Control_t {20 21} Control_t {20 22} Control_t {20 23} Control_t {20 24} Meta_t {20 25} Meta_T {20 26} Meta_t {20 27} Meta_T {20 28} Meta_Control_t {20 29} Meta_Control_t {20 30} Meta_Control_t {20 31} Meta_Control_t {20 32} t {20 33} T {20 34} t {20 35} T {20 36} Control_t {20 37} Control_t {20 38} Control_t {20 39} Control_t {20 40} Meta_t {20 41} Meta_T {20 42} Meta_t {20 43} Meta_T {20 44} Meta_Control_t {20 45} Meta_Control_t {20 46} Meta_Control_t {20 47} Meta_Control_t {20 48} t {20 49} T {20 50} t {20 51} T {20 52} Control_t {20 53} Control_t {20 54} Control_t {20 55} Control_t {20 56} Meta_t {20 57} Meta_T {20 58} Meta_t {20 59} Meta_T {20 60} Meta_Control_t {20 61} Meta_Control_t {20 62} Meta_Control_t {20 63} Meta_Control_t {20 64} T {20 65} t {20 66} T {20 67} t {20 68} Control_t {20 69} Control_t {20 70} Control_t {20 71} Control_t {20 72} Meta_t {20 73} Meta_T {20 74} Meta_t {20 75} Meta_T {20 76} Meta_Control_t {20 77} Meta_Control_t {20 78} Meta_Control_t {20 79} Meta_Control_t {20 80} T {20 81} t {20 82} T {20 83} t {20 84} Control_t {20 85} Control_t {20 86} Control_t {20 87} Control_t {20 88} Meta_t {20 89} Meta_T {20 90} Meta_t {20 91} Meta_T {20 92} Meta_Control_t {20 93} Meta_Control_t {20 94} Meta_Control_t {20 95} Meta_Control_t {20 96} T {20 97} t {20 98} T {20 99} t {20 100} Control_t {20 101} Control_t {20 102} Control_t {20 103} Control_t {20 104} Meta_t {20 105} Meta_T {20 106} Meta_t {20 107} Meta_T {20 108} Meta_Control_t {20 109} Meta_Control_t {20 110} Meta_Control_t {20 111} Meta_Control_t {20 112} T {20 113} t {20 114} T {20 115} t {20 116} Control_t {20 117} Control_t {20 118} Control_t {20 119} Control_t {20 120} Meta_t {20 121} Meta_T {20 122} Meta_t {20 123} Meta_T {20 124} Meta_Control_t {20 125} Meta_Control_t {20 126} Meta_Control_t {20 127} Meta_Control_t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} Control_y {21 5} Control_y {21 6} Control_y {21 7} Control_y {21 8} Meta_y {21 9} Meta_Y {21 10} Meta_y {21 11} Meta_Y {21 12} Meta_Control_y {21 13} Meta_Control_y {21 14} Meta_Control_y {21 15} Meta_Control_y {21 16} y {21 17} Y {21 18} y {21 19} Y {21 20} Control_y {21 21} Control_y {21 22} Control_y {21 23} Control_y {21 24} Meta_y {21 25} Meta_Y {21 26} Meta_y {21 27} Meta_Y {21 28} Meta_Control_y {21 29} Meta_Control_y {21 30} Meta_Control_y {21 31} Meta_Control_y {21 32} y {21 33} Y {21 34} y {21 35} Y {21 36} Control_y {21 37} Control_y {21 38} Control_y {21 39} Control_y {21 40} Meta_y {21 41} Meta_Y {21 42} Meta_y {21 43} Meta_Y {21 44} Meta_Control_y {21 45} Meta_Control_y {21 46} Meta_Control_y {21 47} Meta_Control_y {21 48} y {21 49} Y {21 50} y {21 51} Y {21 52} Control_y {21 53} Control_y {21 54} Control_y {21 55} Control_y {21 56} Meta_y {21 57} Meta_Y {21 58} Meta_y {21 59} Meta_Y {21 60} Meta_Control_y {21 61} Meta_Control_y {21 62} Meta_Control_y {21 63} Meta_Control_y {21 64} Y {21 65} y {21 66} Y {21 67} y {21 68} Control_y {21 69} Control_y {21 70} Control_y {21 71} Control_y {21 72} Meta_y {21 73} Meta_Y {21 74} Meta_y {21 75} Meta_Y {21 76} Meta_Control_y {21 77} Meta_Control_y {21 78} Meta_Control_y {21 79} Meta_Control_y {21 80} Y {21 81} y {21 82} Y {21 83} y {21 84} Control_y {21 85} Control_y {21 86} Control_y {21 87} Control_y {21 88} Meta_y {21 89} Meta_Y {21 90} Meta_y {21 91} Meta_Y {21 92} Meta_Control_y {21 93} Meta_Control_y {21 94} Meta_Control_y {21 95} Meta_Control_y {21 96} Y {21 97} y {21 98} Y {21 99} y {21 100} Control_y {21 101} Control_y {21 102} Control_y {21 103} Control_y {21 104} Meta_y {21 105} Meta_Y {21 106} Meta_y {21 107} Meta_Y {21 108} Meta_Control_y {21 109} Meta_Control_y {21 110} Meta_Control_y {21 111} Meta_Control_y {21 112} Y {21 113} y {21 114} Y {21 115} y {21 116} Control_y {21 117} Control_y {21 118} Control_y {21 119} Control_y {21 120} Meta_y {21 121} Meta_Y {21 122} Meta_y {21 123} Meta_Y {21 124} Meta_Control_y {21 125} Meta_Control_y {21 126} Meta_Control_y {21 127} Meta_Control_y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} Control_u {22 5} Control_u {22 6} Control_u {22 7} Control_u {22 8} Meta_u {22 9} Meta_U {22 10} Meta_u {22 11} Meta_U {22 12} Meta_Control_u {22 13} Meta_Control_u {22 14} Meta_Control_u {22 15} Meta_Control_u {22 16} u {22 17} U {22 18} u {22 19} U {22 20} Control_u {22 21} Control_u {22 22} Control_u {22 23} Control_u {22 24} Meta_u {22 25} Meta_U {22 26} Meta_u {22 27} Meta_U {22 28} Meta_Control_u {22 29} Meta_Control_u {22 30} Meta_Control_u {22 31} Meta_Control_u {22 32} u {22 33} U {22 34} u {22 35} U {22 36} Control_u {22 37} Control_u {22 38} Control_u {22 39} Control_u {22 40} Meta_u {22 41} Meta_U {22 42} Meta_u {22 43} Meta_U {22 44} Meta_Control_u {22 45} Meta_Control_u {22 46} Meta_Control_u {22 47} Meta_Control_u {22 48} u {22 49} U {22 50} u {22 51} U {22 52} Control_u {22 53} Control_u {22 54} Control_u {22 55} Control_u {22 56} Meta_u {22 57} Meta_U {22 58} Meta_u {22 59} Meta_U {22 60} Meta_Control_u {22 61} Meta_Control_u {22 62} Meta_Control_u {22 63} Meta_Control_u {22 64} U {22 65} u {22 66} U {22 67} u {22 68} Control_u {22 69} Control_u {22 70} Control_u {22 71} Control_u {22 72} Meta_u {22 73} Meta_U {22 74} Meta_u {22 75} Meta_U {22 76} Meta_Control_u {22 77} Meta_Control_u {22 78} Meta_Control_u {22 79} Meta_Control_u {22 80} U {22 81} u {22 82} U {22 83} u {22 84} Control_u {22 85} Control_u {22 86} Control_u {22 87} Control_u {22 88} Meta_u {22 89} Meta_U {22 90} Meta_u {22 91} Meta_U {22 92} Meta_Control_u {22 93} Meta_Control_u {22 94} Meta_Control_u {22 95} Meta_Control_u {22 96} U {22 97} u {22 98} U {22 99} u {22 100} Control_u {22 101} Control_u {22 102} Control_u {22 103} Control_u {22 104} Meta_u {22 105} Meta_U {22 106} Meta_u {22 107} Meta_U {22 108} Meta_Control_u {22 109} Meta_Control_u {22 110} Meta_Control_u {22 111} Meta_Control_u {22 112} U {22 113} u {22 114} U {22 115} u {22 116} Control_u {22 117} Control_u {22 118} Control_u {22 119} Control_u {22 120} Meta_u {22 121} Meta_U {22 122} Meta_u {22 123} Meta_U {22 124} Meta_Control_u {22 125} Meta_Control_u {22 126} Meta_Control_u {22 127} Meta_Control_u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} Tab {23 5} Tab {23 6} Tab {23 7} Tab {23 8} Meta_i {23 9} Meta_I {23 10} Meta_i {23 11} Meta_I {23 12} Meta_Tab {23 13} Meta_Tab {23 14} Meta_Tab {23 15} Meta_Tab {23 16} i {23 17} I {23 18} i {23 19} I {23 20} Tab {23 21} Tab {23 22} Tab {23 23} Tab {23 24} Meta_i {23 25} Meta_I {23 26} Meta_i {23 27} Meta_I {23 28} Meta_Tab {23 29} Meta_Tab {23 30} Meta_Tab {23 31} Meta_Tab {23 32} i {23 33} I {23 34} i {23 35} I {23 36} Tab {23 37} Tab {23 38} Tab {23 39} Tab {23 40} Meta_i {23 41} Meta_I {23 42} Meta_i {23 43} Meta_I {23 44} Meta_Tab {23 45} Meta_Tab {23 46} Meta_Tab {23 47} Meta_Tab {23 48} i {23 49} I {23 50} i {23 51} I {23 52} Tab {23 53} Tab {23 54} Tab {23 55} Tab {23 56} Meta_i {23 57} Meta_I {23 58} Meta_i {23 59} Meta_I {23 60} Meta_Tab {23 61} Meta_Tab {23 62} Meta_Tab {23 63} Meta_Tab {23 64} I {23 65} i {23 66} I {23 67} i {23 68} Tab {23 69} Tab {23 70} Tab {23 71} Tab {23 72} Meta_i {23 73} Meta_I {23 74} Meta_i {23 75} Meta_I {23 76} Meta_Tab {23 77} Meta_Tab {23 78} Meta_Tab {23 79} Meta_Tab {23 80} I {23 81} i {23 82} I {23 83} i {23 84} Tab {23 85} Tab {23 86} Tab {23 87} Tab {23 88} Meta_i {23 89} Meta_I {23 90} Meta_i {23 91} Meta_I {23 92} Meta_Tab {23 93} Meta_Tab {23 94} Meta_Tab {23 95} Meta_Tab {23 96} I {23 97} i {23 98} I {23 99} i {23 100} Tab {23 101} Tab {23 102} Tab {23 103} Tab {23 104} Meta_i {23 105} Meta_I {23 106} Meta_i {23 107} Meta_I {23 108} Meta_Tab {23 109} Meta_Tab {23 110} Meta_Tab {23 111} Meta_Tab {23 112} I {23 113} i {23 114} I {23 115} i {23 116} Tab {23 117} Tab {23 118} Tab {23 119} Tab {23 120} Meta_i {23 121} Meta_I {23 122} Meta_i {23 123} Meta_I {23 124} Meta_Tab {23 125} Meta_Tab {23 126} Meta_Tab {23 127} Meta_Tab {24 0} o {24 1} O {24 2} o {24 3} O {24 4} Control_o {24 5} Control_o {24 6} Control_o {24 7} Control_o {24 8} Meta_o {24 9} Meta_O {24 10} Meta_o {24 11} Meta_O {24 12} Meta_Control_o {24 13} Meta_Control_o {24 14} Meta_Control_o {24 15} Meta_Control_o {24 16} o {24 17} O {24 18} o {24 19} O {24 20} Control_o {24 21} Control_o {24 22} Control_o {24 23} Control_o {24 24} Meta_o {24 25} Meta_O {24 26} Meta_o {24 27} Meta_O {24 28} Meta_Control_o {24 29} Meta_Control_o {24 30} Meta_Control_o {24 31} Meta_Control_o {24 32} o {24 33} O {24 34} o {24 35} O {24 36} Control_o {24 37} Control_o {24 38} Control_o {24 39} Control_o {24 40} Meta_o {24 41} Meta_O {24 42} Meta_o {24 43} Meta_O {24 44} Meta_Control_o {24 45} Meta_Control_o {24 46} Meta_Control_o {24 47} Meta_Control_o {24 48} o {24 49} O {24 50} o {24 51} O {24 52} Control_o {24 53} Control_o {24 54} Control_o {24 55} Control_o {24 56} Meta_o {24 57} Meta_O {24 58} Meta_o {24 59} Meta_O {24 60} Meta_Control_o {24 61} Meta_Control_o {24 62} Meta_Control_o {24 63} Meta_Control_o {24 64} O {24 65} o {24 66} O {24 67} o {24 68} Control_o {24 69} Control_o {24 70} Control_o {24 71} Control_o {24 72} Meta_o {24 73} Meta_O {24 74} Meta_o {24 75} Meta_O {24 76} Meta_Control_o {24 77} Meta_Control_o {24 78} Meta_Control_o {24 79} Meta_Control_o {24 80} O {24 81} o {24 82} O {24 83} o {24 84} Control_o {24 85} Control_o {24 86} Control_o {24 87} Control_o {24 88} Meta_o {24 89} Meta_O {24 90} Meta_o {24 91} Meta_O {24 92} Meta_Control_o {24 93} Meta_Control_o {24 94} Meta_Control_o {24 95} Meta_Control_o {24 96} O {24 97} o {24 98} O {24 99} o {24 100} Control_o {24 101} Control_o {24 102} Control_o {24 103} Control_o {24 104} Meta_o {24 105} Meta_O {24 106} Meta_o {24 107} Meta_O {24 108} Meta_Control_o {24 109} Meta_Control_o {24 110} Meta_Control_o {24 111} Meta_Control_o {24 112} O {24 113} o {24 114} O {24 115} o {24 116} Control_o {24 117} Control_o {24 118} Control_o {24 119} Control_o {24 120} Meta_o {24 121} Meta_O {24 122} Meta_o {24 123} Meta_O {24 124} Meta_Control_o {24 125} Meta_Control_o {24 126} Meta_Control_o {24 127} Meta_Control_o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} Control_p {25 5} Control_p {25 6} Control_p {25 7} Control_p {25 8} Meta_p {25 9} Meta_P {25 10} Meta_p {25 11} Meta_P {25 12} Meta_Control_p {25 13} Meta_Control_p {25 14} Meta_Control_p {25 15} Meta_Control_p {25 16} p {25 17} P {25 18} p {25 19} P {25 20} Control_p {25 21} Control_p {25 22} Control_p {25 23} Control_p {25 24} Meta_p {25 25} Meta_P {25 26} Meta_p {25 27} Meta_P {25 28} Meta_Control_p {25 29} Meta_Control_p {25 30} Meta_Control_p {25 31} Meta_Control_p {25 32} p {25 33} P {25 34} p {25 35} P {25 36} Control_p {25 37} Control_p {25 38} Control_p {25 39} Control_p {25 40} Meta_p {25 41} Meta_P {25 42} Meta_p {25 43} Meta_P {25 44} Meta_Control_p {25 45} Meta_Control_p {25 46} Meta_Control_p {25 47} Meta_Control_p {25 48} p {25 49} P {25 50} p {25 51} P {25 52} Control_p {25 53} Control_p {25 54} Control_p {25 55} Control_p {25 56} Meta_p {25 57} Meta_P {25 58} Meta_p {25 59} Meta_P {25 60} Meta_Control_p {25 61} Meta_Control_p {25 62} Meta_Control_p {25 63} Meta_Control_p {25 64} P {25 65} p {25 66} P {25 67} p {25 68} Control_p {25 69} Control_p {25 70} Control_p {25 71} Control_p {25 72} Meta_p {25 73} Meta_P {25 74} Meta_p {25 75} Meta_P {25 76} Meta_Control_p {25 77} Meta_Control_p {25 78} Meta_Control_p {25 79} Meta_Control_p {25 80} P {25 81} p {25 82} P {25 83} p {25 84} Control_p {25 85} Control_p {25 86} Control_p {25 87} Control_p {25 88} Meta_p {25 89} Meta_P {25 90} Meta_p {25 91} Meta_P {25 92} Meta_Control_p {25 93} Meta_Control_p {25 94} Meta_Control_p {25 95} Meta_Control_p {25 96} P {25 97} p {25 98} P {25 99} p {25 100} Control_p {25 101} Control_p {25 102} Control_p {25 103} Control_p {25 104} Meta_p {25 105} Meta_P {25 106} Meta_p {25 107} Meta_P {25 108} Meta_Control_p {25 109} Meta_Control_p {25 110} Meta_Control_p {25 111} Meta_Control_p {25 112} P {25 113} p {25 114} P {25 115} p {25 116} Control_p {25 117} Control_p {25 118} Control_p {25 119} Control_p {25 120} Meta_p {25 121} Meta_P {25 122} Meta_p {25 123} Meta_P {25 124} Meta_Control_p {25 125} Meta_Control_p {25 126} Meta_Control_p {25 127} Meta_Control_p {26 0} bracketleft {26 1} braceleft {26 2} bracketleft {26 3} braceleft {26 4} Escape {26 5} Escape {26 6} Escape {26 7} Escape {26 8} Meta_bracketleft {26 9} Meta_braceleft {26 10} Meta_bracketleft {26 11} Meta_braceleft {26 12} Meta_Escape {26 13} Meta_Escape {26 14} Meta_Escape {26 15} Meta_Escape {26 16} bracketleft {26 17} braceleft {26 18} bracketleft {26 19} braceleft {26 20} Escape {26 21} Escape {26 22} Escape {26 23} Escape {26 24} Meta_bracketleft {26 25} Meta_braceleft {26 26} Meta_bracketleft {26 27} Meta_braceleft {26 28} Meta_Escape {26 29} Meta_Escape {26 30} Meta_Escape {26 31} Meta_Escape {26 32} bracketleft {26 33} braceleft {26 34} bracketleft {26 35} braceleft {26 36} Escape {26 37} Escape {26 38} Escape {26 39} Escape {26 40} Meta_bracketleft {26 41} Meta_braceleft {26 42} Meta_bracketleft {26 43} Meta_braceleft {26 44} Meta_Escape {26 45} Meta_Escape {26 46} Meta_Escape {26 47} Meta_Escape {26 48} bracketleft {26 49} braceleft {26 50} bracketleft {26 51} braceleft {26 52} Escape {26 53} Escape {26 54} Escape {26 55} Escape {26 56} Meta_bracketleft {26 57} Meta_braceleft {26 58} Meta_bracketleft {26 59} Meta_braceleft {26 60} Meta_Escape {26 61} Meta_Escape {26 62} Meta_Escape {26 63} Meta_Escape {26 64} bracketleft {26 65} braceleft {26 66} bracketleft {26 67} braceleft {26 68} Escape {26 69} Escape {26 70} Escape {26 71} Escape {26 72} Meta_bracketleft {26 73} Meta_braceleft {26 74} Meta_bracketleft {26 75} Meta_braceleft {26 76} Meta_Escape {26 77} Meta_Escape {26 78} Meta_Escape {26 79} Meta_Escape {26 80} bracketleft {26 81} braceleft {26 82} bracketleft {26 83} braceleft {26 84} Escape {26 85} Escape {26 86} Escape {26 87} Escape {26 88} Meta_bracketleft {26 89} Meta_braceleft {26 90} Meta_bracketleft {26 91} Meta_braceleft {26 92} Meta_Escape {26 93} Meta_Escape {26 94} Meta_Escape {26 95} Meta_Escape {26 96} bracketleft {26 97} braceleft {26 98} bracketleft {26 99} braceleft {26 100} Escape {26 101} Escape {26 102} Escape {26 103} Escape {26 104} Meta_bracketleft {26 105} Meta_braceleft {26 106} Meta_bracketleft {26 107} Meta_braceleft {26 108} Meta_Escape {26 109} Meta_Escape {26 110} Meta_Escape {26 111} Meta_Escape {26 112} bracketleft {26 113} braceleft {26 114} bracketleft {26 115} braceleft {26 116} Escape {26 117} Escape {26 118} Escape {26 119} Escape {26 120} Meta_bracketleft {26 121} Meta_braceleft {26 122} Meta_bracketleft {26 123} Meta_braceleft {26 124} Meta_Escape {26 125} Meta_Escape {26 126} Meta_Escape {26 127} Meta_Escape {27 0} bracketright {27 1} braceright {27 2} bracketright {27 3} braceright {27 4} Control_bracketright {27 5} Control_bracketright {27 6} Control_bracketright {27 7} Control_bracketright {27 8} Meta_bracketright {27 9} Meta_braceright {27 10} Meta_bracketright {27 11} Meta_braceright {27 12} Meta_Control_bracketright {27 13} Meta_Control_bracketright {27 14} Meta_Control_bracketright {27 15} Meta_Control_bracketright {27 16} bracketright {27 17} braceright {27 18} bracketright {27 19} braceright {27 20} Control_bracketright {27 21} Control_bracketright {27 22} Control_bracketright {27 23} Control_bracketright {27 24} Meta_bracketright {27 25} Meta_braceright {27 26} Meta_bracketright {27 27} Meta_braceright {27 28} Meta_Control_bracketright {27 29} Meta_Control_bracketright {27 30} Meta_Control_bracketright {27 31} Meta_Control_bracketright {27 32} bracketright {27 33} braceright {27 34} bracketright {27 35} braceright {27 36} Control_bracketright {27 37} Control_bracketright {27 38} Control_bracketright {27 39} Control_bracketright {27 40} Meta_bracketright {27 41} Meta_braceright {27 42} Meta_bracketright {27 43} Meta_braceright {27 44} Meta_Control_bracketright {27 45} Meta_Control_bracketright {27 46} Meta_Control_bracketright {27 47} Meta_Control_bracketright {27 48} bracketright {27 49} braceright {27 50} bracketright {27 51} braceright {27 52} Control_bracketright {27 53} Control_bracketright {27 54} Control_bracketright {27 55} Control_bracketright {27 56} Meta_bracketright {27 57} Meta_braceright {27 58} Meta_bracketright {27 59} Meta_braceright {27 60} Meta_Control_bracketright {27 61} Meta_Control_bracketright {27 62} Meta_Control_bracketright {27 63} Meta_Control_bracketright {27 64} bracketright {27 65} braceright {27 66} bracketright {27 67} braceright {27 68} Control_bracketright {27 69} Control_bracketright {27 70} Control_bracketright {27 71} Control_bracketright {27 72} Meta_bracketright {27 73} Meta_braceright {27 74} Meta_bracketright {27 75} Meta_braceright {27 76} Meta_Control_bracketright {27 77} Meta_Control_bracketright {27 78} Meta_Control_bracketright {27 79} Meta_Control_bracketright {27 80} bracketright {27 81} braceright {27 82} bracketright {27 83} braceright {27 84} Control_bracketright {27 85} Control_bracketright {27 86} Control_bracketright {27 87} Control_bracketright {27 88} Meta_bracketright {27 89} Meta_braceright {27 90} Meta_bracketright {27 91} Meta_braceright {27 92} Meta_Control_bracketright {27 93} Meta_Control_bracketright {27 94} Meta_Control_bracketright {27 95} Meta_Control_bracketright {27 96} bracketright {27 97} braceright {27 98} bracketright {27 99} braceright {27 100} Control_bracketright {27 101} Control_bracketright {27 102} Control_bracketright {27 103} Control_bracketright {27 104} Meta_bracketright {27 105} Meta_braceright {27 106} Meta_bracketright {27 107} Meta_braceright {27 108} Meta_Control_bracketright {27 109} Meta_Control_bracketright {27 110} Meta_Control_bracketright {27 111} Meta_Control_bracketright {27 112} bracketright {27 113} braceright {27 114} bracketright {27 115} braceright {27 116} Control_bracketright {27 117} Control_bracketright {27 118} Control_bracketright {27 119} Control_bracketright {27 120} Meta_bracketright {27 121} Meta_braceright {27 122} Meta_bracketright {27 123} Meta_braceright {27 124} Meta_Control_bracketright {27 125} Meta_Control_bracketright {27 126} Meta_Control_bracketright {27 127} Meta_Control_bracketright {28 0} Return {28 1} Return {28 2} Return {28 3} Return {28 4} Control_m {28 5} Control_m {28 6} Control_m {28 7} Control_m {28 8} Meta_Control_m {28 9} Meta_Control_m {28 10} Meta_Control_m {28 11} Meta_Control_m {28 12} Meta_Control_m {28 13} Meta_Control_m {28 14} Meta_Control_m {28 15} Meta_Control_m {28 16} Return {28 17} Return {28 18} Return {28 19} Return {28 20} Control_m {28 21} Control_m {28 22} Control_m {28 23} Control_m {28 24} Meta_Control_m {28 25} Meta_Control_m {28 26} Meta_Control_m {28 27} Meta_Control_m {28 28} Meta_Control_m {28 29} Meta_Control_m {28 30} Meta_Control_m {28 31} Meta_Control_m {28 32} Return {28 33} Return {28 34} Return {28 35} Return {28 36} Control_m {28 37} Control_m {28 38} Control_m {28 39} Control_m {28 40} Meta_Control_m {28 41} Meta_Control_m {28 42} Meta_Control_m {28 43} Meta_Control_m {28 44} Meta_Control_m {28 45} Meta_Control_m {28 46} Meta_Control_m {28 47} Meta_Control_m {28 48} Return {28 49} Return {28 50} Return {28 51} Return {28 52} Control_m {28 53} Control_m {28 54} Control_m {28 55} Control_m {28 56} Meta_Control_m {28 57} Meta_Control_m {28 58} Meta_Control_m {28 59} Meta_Control_m {28 60} Meta_Control_m {28 61} Meta_Control_m {28 62} Meta_Control_m {28 63} Meta_Control_m {28 64} Return {28 65} Return {28 66} Return {28 67} Return {28 68} Control_m {28 69} Control_m {28 70} Control_m {28 71} Control_m {28 72} Meta_Control_m {28 73} Meta_Control_m {28 74} Meta_Control_m {28 75} Meta_Control_m {28 76} Meta_Control_m {28 77} Meta_Control_m {28 78} Meta_Control_m {28 79} Meta_Control_m {28 80} Return {28 81} Return {28 82} Return {28 83} Return {28 84} Control_m {28 85} Control_m {28 86} Control_m {28 87} Control_m {28 88} Meta_Control_m {28 89} Meta_Control_m {28 90} Meta_Control_m {28 91} Meta_Control_m {28 92} Meta_Control_m {28 93} Meta_Control_m {28 94} Meta_Control_m {28 95} Meta_Control_m {28 96} Return {28 97} Return {28 98} Return {28 99} Return {28 100} Control_m {28 101} Control_m {28 102} Control_m {28 103} Control_m {28 104} Meta_Control_m {28 105} Meta_Control_m {28 106} Meta_Control_m {28 107} Meta_Control_m {28 108} Meta_Control_m {28 109} Meta_Control_m {28 110} Meta_Control_m {28 111} Meta_Control_m {28 112} Return {28 113} Return {28 114} Return {28 115} Return {28 116} Control_m {28 117} Control_m {28 118} Control_m {28 119} Control_m {28 120} Meta_Control_m {28 121} Meta_Control_m {28 122} Meta_Control_m {28 123} Meta_Control_m {28 124} Meta_Control_m {28 125} Meta_Control_m {28 126} Meta_Control_m {28 127} Meta_Control_m {29 0} Control {29 1} Control {29 2} Control {29 3} Control {29 4} Control {29 5} Control {29 6} Control {29 7} Control {29 8} Control {29 9} Control {29 10} Control {29 11} Control {29 12} Control {29 13} Control {29 14} Control {29 15} Control {29 16} Control {29 17} Control {29 18} Control {29 19} Control {29 20} Control {29 21} Control {29 22} Control {29 23} Control {29 24} Control {29 25} Control {29 26} Control {29 27} Control {29 28} Control {29 29} Control {29 30} Control {29 31} Control {29 32} Control {29 33} Control {29 34} Control {29 35} Control {29 36} Control {29 37} Control {29 38} Control {29 39} Control {29 40} Control {29 41} Control {29 42} Control {29 43} Control {29 44} Control {29 45} Control {29 46} Control {29 47} Control {29 48} Control {29 49} Control {29 50} Control {29 51} Control {29 52} Control {29 53} Control {29 54} Control {29 55} Control {29 56} Control {29 57} Control {29 58} Control {29 59} Control {29 60} Control {29 61} Control {29 62} Control {29 63} Control {29 64} Control {29 65} Control {29 66} Control {29 67} Control {29 68} Control {29 69} Control {29 70} Control {29 71} Control {29 72} Control {29 73} Control {29 74} Control {29 75} Control {29 76} Control {29 77} Control {29 78} Control {29 79} Control {29 80} Control {29 81} Control {29 82} Control {29 83} Control {29 84} Control {29 85} Control {29 86} Control {29 87} Control {29 88} Control {29 89} Control {29 90} Control {29 91} Control {29 92} Control {29 93} Control {29 94} Control {29 95} Control {29 96} Control {29 97} Control {29 98} Control {29 99} Control {29 100} Control {29 101} Control {29 102} Control {29 103} Control {29 104} Control {29 105} Control {29 106} Control {29 107} Control {29 108} Control {29 109} Control {29 110} Control {29 111} Control {29 112} Control {29 113} Control {29 114} Control {29 115} Control {29 116} Control {29 117} Control {29 118} Control {29 119} Control {29 120} Control {29 121} Control {29 122} Control {29 123} Control {29 124} Control {29 125} Control {29 126} Control {29 127} Control {30 0} a {30 1} A {30 2} a {30 3} A {30 4} Control_a {30 5} Control_a {30 6} Control_a {30 7} Control_a {30 8} Meta_a {30 9} Meta_A {30 10} Meta_a {30 11} Meta_A {30 12} Meta_Control_a {30 13} Meta_Control_a {30 14} Meta_Control_a {30 15} Meta_Control_a {30 16} a {30 17} A {30 18} a {30 19} A {30 20} Control_a {30 21} Control_a {30 22} Control_a {30 23} Control_a {30 24} Meta_a {30 25} Meta_A {30 26} Meta_a {30 27} Meta_A {30 28} Meta_Control_a {30 29} Meta_Control_a {30 30} Meta_Control_a {30 31} Meta_Control_a {30 32} a {30 33} A {30 34} a {30 35} A {30 36} Control_a {30 37} Control_a {30 38} Control_a {30 39} Control_a {30 40} Meta_a {30 41} Meta_A {30 42} Meta_a {30 43} Meta_A {30 44} Meta_Control_a {30 45} Meta_Control_a {30 46} Meta_Control_a {30 47} Meta_Control_a {30 48} a {30 49} A {30 50} a {30 51} A {30 52} Control_a {30 53} Control_a {30 54} Control_a {30 55} Control_a {30 56} Meta_a {30 57} Meta_A {30 58} Meta_a {30 59} Meta_A {30 60} Meta_Control_a {30 61} Meta_Control_a {30 62} Meta_Control_a {30 63} Meta_Control_a {30 64} A {30 65} a {30 66} A {30 67} a {30 68} Control_a {30 69} Control_a {30 70} Control_a {30 71} Control_a {30 72} Meta_a {30 73} Meta_A {30 74} Meta_a {30 75} Meta_A {30 76} Meta_Control_a {30 77} Meta_Control_a {30 78} Meta_Control_a {30 79} Meta_Control_a {30 80} A {30 81} a {30 82} A {30 83} a {30 84} Control_a {30 85} Control_a {30 86} Control_a {30 87} Control_a {30 88} Meta_a {30 89} Meta_A {30 90} Meta_a {30 91} Meta_A {30 92} Meta_Control_a {30 93} Meta_Control_a {30 94} Meta_Control_a {30 95} Meta_Control_a {30 96} A {30 97} a {30 98} A {30 99} a {30 100} Control_a {30 101} Control_a {30 102} Control_a {30 103} Control_a {30 104} Meta_a {30 105} Meta_A {30 106} Meta_a {30 107} Meta_A {30 108} Meta_Control_a {30 109} Meta_Control_a {30 110} Meta_Control_a {30 111} Meta_Control_a {30 112} A {30 113} a {30 114} A {30 115} a {30 116} Control_a {30 117} Control_a {30 118} Control_a {30 119} Control_a {30 120} Meta_a {30 121} Meta_A {30 122} Meta_a {30 123} Meta_A {30 124} Meta_Control_a {30 125} Meta_Control_a {30 126} Meta_Control_a {30 127} Meta_Control_a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} Control_s {31 5} Control_s {31 6} Control_s {31 7} Control_s {31 8} Meta_s {31 9} Meta_S {31 10} Meta_s {31 11} Meta_S {31 12} Meta_Control_s {31 13} Meta_Control_s {31 14} Meta_Control_s {31 15} Meta_Control_s {31 16} s {31 17} S {31 18} s {31 19} S {31 20} Control_s {31 21} Control_s {31 22} Control_s {31 23} Control_s {31 24} Meta_s {31 25} Meta_S {31 26} Meta_s {31 27} Meta_S {31 28} Meta_Control_s {31 29} Meta_Control_s {31 30} Meta_Control_s {31 31} Meta_Control_s {31 32} s {31 33} S {31 34} s {31 35} S {31 36} Control_s {31 37} Control_s {31 38} Control_s {31 39} Control_s {31 40} Meta_s {31 41} Meta_S {31 42} Meta_s {31 43} Meta_S {31 44} Meta_Control_s {31 45} Meta_Control_s {31 46} Meta_Control_s {31 47} Meta_Control_s {31 48} s {31 49} S {31 50} s {31 51} S {31 52} Control_s {31 53} Control_s {31 54} Control_s {31 55} Control_s {31 56} Meta_s {31 57} Meta_S {31 58} Meta_s {31 59} Meta_S {31 60} Meta_Control_s {31 61} Meta_Control_s {31 62} Meta_Control_s {31 63} Meta_Control_s {31 64} S {31 65} s {31 66} S {31 67} s {31 68} Control_s {31 69} Control_s {31 70} Control_s {31 71} Control_s {31 72} Meta_s {31 73} Meta_S {31 74} Meta_s {31 75} Meta_S {31 76} Meta_Control_s {31 77} Meta_Control_s {31 78} Meta_Control_s {31 79} Meta_Control_s {31 80} S {31 81} s {31 82} S {31 83} s {31 84} Control_s {31 85} Control_s {31 86} Control_s {31 87} Control_s {31 88} Meta_s {31 89} Meta_S {31 90} Meta_s {31 91} Meta_S {31 92} Meta_Control_s {31 93} Meta_Control_s {31 94} Meta_Control_s {31 95} Meta_Control_s {31 96} S {31 97} s {31 98} S {31 99} s {31 100} Control_s {31 101} Control_s {31 102} Control_s {31 103} Control_s {31 104} Meta_s {31 105} Meta_S {31 106} Meta_s {31 107} Meta_S {31 108} Meta_Control_s {31 109} Meta_Control_s {31 110} Meta_Control_s {31 111} Meta_Control_s {31 112} S {31 113} s {31 114} S {31 115} s {31 116} Control_s {31 117} Control_s {31 118} Control_s {31 119} Control_s {31 120} Meta_s {31 121} Meta_S {31 122} Meta_s {31 123} Meta_S {31 124} Meta_Control_s {31 125} Meta_Control_s {31 126} Meta_Control_s {31 127} Meta_Control_s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} Control_d {32 5} Control_d {32 6} Control_d {32 7} Control_d {32 8} Meta_d {32 9} Meta_D {32 10} Meta_d {32 11} Meta_D {32 12} Meta_Control_d {32 13} Meta_Control_d {32 14} Meta_Control_d {32 15} Meta_Control_d {32 16} d {32 17} D {32 18} d {32 19} D {32 20} Control_d {32 21} Control_d {32 22} Control_d {32 23} Control_d {32 24} Meta_d {32 25} Meta_D {32 26} Meta_d {32 27} Meta_D {32 28} Meta_Control_d {32 29} Meta_Control_d {32 30} Meta_Control_d {32 31} Meta_Control_d {32 32} d {32 33} D {32 34} d {32 35} D {32 36} Control_d {32 37} Control_d {32 38} Control_d {32 39} Control_d {32 40} Meta_d {32 41} Meta_D {32 42} Meta_d {32 43} Meta_D {32 44} Meta_Control_d {32 45} Meta_Control_d {32 46} Meta_Control_d {32 47} Meta_Control_d {32 48} d {32 49} D {32 50} d {32 51} D {32 52} Control_d {32 53} Control_d {32 54} Control_d {32 55} Control_d {32 56} Meta_d {32 57} Meta_D {32 58} Meta_d {32 59} Meta_D {32 60} Meta_Control_d {32 61} Meta_Control_d {32 62} Meta_Control_d {32 63} Meta_Control_d {32 64} D {32 65} d {32 66} D {32 67} d {32 68} Control_d {32 69} Control_d {32 70} Control_d {32 71} Control_d {32 72} Meta_d {32 73} Meta_D {32 74} Meta_d {32 75} Meta_D {32 76} Meta_Control_d {32 77} Meta_Control_d {32 78} Meta_Control_d {32 79} Meta_Control_d {32 80} D {32 81} d {32 82} D {32 83} d {32 84} Control_d {32 85} Control_d {32 86} Control_d {32 87} Control_d {32 88} Meta_d {32 89} Meta_D {32 90} Meta_d {32 91} Meta_D {32 92} Meta_Control_d {32 93} Meta_Control_d {32 94} Meta_Control_d {32 95} Meta_Control_d {32 96} D {32 97} d {32 98} D {32 99} d {32 100} Control_d {32 101} Control_d {32 102} Control_d {32 103} Control_d {32 104} Meta_d {32 105} Meta_D {32 106} Meta_d {32 107} Meta_D {32 108} Meta_Control_d {32 109} Meta_Control_d {32 110} Meta_Control_d {32 111} Meta_Control_d {32 112} D {32 113} d {32 114} D {32 115} d {32 116} Control_d {32 117} Control_d {32 118} Control_d {32 119} Control_d {32 120} Meta_d {32 121} Meta_D {32 122} Meta_d {32 123} Meta_D {32 124} Meta_Control_d {32 125} Meta_Control_d {32 126} Meta_Control_d {32 127} Meta_Control_d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} Control_f {33 5} Control_f {33 6} Control_f {33 7} Control_f {33 8} Meta_f {33 9} Meta_F {33 10} Meta_f {33 11} Meta_F {33 12} Meta_Control_f {33 13} Meta_Control_f {33 14} Meta_Control_f {33 15} Meta_Control_f {33 16} f {33 17} F {33 18} f {33 19} F {33 20} Control_f {33 21} Control_f {33 22} Control_f {33 23} Control_f {33 24} Meta_f {33 25} Meta_F {33 26} Meta_f {33 27} Meta_F {33 28} Meta_Control_f {33 29} Meta_Control_f {33 30} Meta_Control_f {33 31} Meta_Control_f {33 32} f {33 33} F {33 34} f {33 35} F {33 36} Control_f {33 37} Control_f {33 38} Control_f {33 39} Control_f {33 40} Meta_f {33 41} Meta_F {33 42} Meta_f {33 43} Meta_F {33 44} Meta_Control_f {33 45} Meta_Control_f {33 46} Meta_Control_f {33 47} Meta_Control_f {33 48} f {33 49} F {33 50} f {33 51} F {33 52} Control_f {33 53} Control_f {33 54} Control_f {33 55} Control_f {33 56} Meta_f {33 57} Meta_F {33 58} Meta_f {33 59} Meta_F {33 60} Meta_Control_f {33 61} Meta_Control_f {33 62} Meta_Control_f {33 63} Meta_Control_f {33 64} F {33 65} f {33 66} F {33 67} f {33 68} Control_f {33 69} Control_f {33 70} Control_f {33 71} Control_f {33 72} Meta_f {33 73} Meta_F {33 74} Meta_f {33 75} Meta_F {33 76} Meta_Control_f {33 77} Meta_Control_f {33 78} Meta_Control_f {33 79} Meta_Control_f {33 80} F {33 81} f {33 82} F {33 83} f {33 84} Control_f {33 85} Control_f {33 86} Control_f {33 87} Control_f {33 88} Meta_f {33 89} Meta_F {33 90} Meta_f {33 91} Meta_F {33 92} Meta_Control_f {33 93} Meta_Control_f {33 94} Meta_Control_f {33 95} Meta_Control_f {33 96} F {33 97} f {33 98} F {33 99} f {33 100} Control_f {33 101} Control_f {33 102} Control_f {33 103} Control_f {33 104} Meta_f {33 105} Meta_F {33 106} Meta_f {33 107} Meta_F {33 108} Meta_Control_f {33 109} Meta_Control_f {33 110} Meta_Control_f {33 111} Meta_Control_f {33 112} F {33 113} f {33 114} F {33 115} f {33 116} Control_f {33 117} Control_f {33 118} Control_f {33 119} Control_f {33 120} Meta_f {33 121} Meta_F {33 122} Meta_f {33 123} Meta_F {33 124} Meta_Control_f {33 125} Meta_Control_f {33 126} Meta_Control_f {33 127} Meta_Control_f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} Control_g {34 5} Control_g {34 6} Control_g {34 7} Control_g {34 8} Meta_g {34 9} Meta_G {34 10} Meta_g {34 11} Meta_G {34 12} Meta_Control_g {34 13} Meta_Control_g {34 14} Meta_Control_g {34 15} Meta_Control_g {34 16} g {34 17} G {34 18} g {34 19} G {34 20} Control_g {34 21} Control_g {34 22} Control_g {34 23} Control_g {34 24} Meta_g {34 25} Meta_G {34 26} Meta_g {34 27} Meta_G {34 28} Meta_Control_g {34 29} Meta_Control_g {34 30} Meta_Control_g {34 31} Meta_Control_g {34 32} g {34 33} G {34 34} g {34 35} G {34 36} Control_g {34 37} Control_g {34 38} Control_g {34 39} Control_g {34 40} Meta_g {34 41} Meta_G {34 42} Meta_g {34 43} Meta_G {34 44} Meta_Control_g {34 45} Meta_Control_g {34 46} Meta_Control_g {34 47} Meta_Control_g {34 48} g {34 49} G {34 50} g {34 51} G {34 52} Control_g {34 53} Control_g {34 54} Control_g {34 55} Control_g {34 56} Meta_g {34 57} Meta_G {34 58} Meta_g {34 59} Meta_G {34 60} Meta_Control_g {34 61} Meta_Control_g {34 62} Meta_Control_g {34 63} Meta_Control_g {34 64} G {34 65} g {34 66} G {34 67} g {34 68} Control_g {34 69} Control_g {34 70} Control_g {34 71} Control_g {34 72} Meta_g {34 73} Meta_G {34 74} Meta_g {34 75} Meta_G {34 76} Meta_Control_g {34 77} Meta_Control_g {34 78} Meta_Control_g {34 79} Meta_Control_g {34 80} G {34 81} g {34 82} G {34 83} g {34 84} Control_g {34 85} Control_g {34 86} Control_g {34 87} Control_g {34 88} Meta_g {34 89} Meta_G {34 90} Meta_g {34 91} Meta_G {34 92} Meta_Control_g {34 93} Meta_Control_g {34 94} Meta_Control_g {34 95} Meta_Control_g {34 96} G {34 97} g {34 98} G {34 99} g {34 100} Control_g {34 101} Control_g {34 102} Control_g {34 103} Control_g {34 104} Meta_g {34 105} Meta_G {34 106} Meta_g {34 107} Meta_G {34 108} Meta_Control_g {34 109} Meta_Control_g {34 110} Meta_Control_g {34 111} Meta_Control_g {34 112} G {34 113} g {34 114} G {34 115} g {34 116} Control_g {34 117} Control_g {34 118} Control_g {34 119} Control_g {34 120} Meta_g {34 121} Meta_G {34 122} Meta_g {34 123} Meta_G {34 124} Meta_Control_g {34 125} Meta_Control_g {34 126} Meta_Control_g {34 127} Meta_Control_g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} BackSpace {35 5} BackSpace {35 6} BackSpace {35 7} BackSpace {35 8} Meta_h {35 9} Meta_H {35 10} Meta_h {35 11} Meta_H {35 12} Meta_BackSpace {35 13} Meta_BackSpace {35 14} Meta_BackSpace {35 15} Meta_BackSpace {35 16} h {35 17} H {35 18} h {35 19} H {35 20} BackSpace {35 21} BackSpace {35 22} BackSpace {35 23} BackSpace {35 24} Meta_h {35 25} Meta_H {35 26} Meta_h {35 27} Meta_H {35 28} Meta_BackSpace {35 29} Meta_BackSpace {35 30} Meta_BackSpace {35 31} Meta_BackSpace {35 32} h {35 33} H {35 34} h {35 35} H {35 36} BackSpace {35 37} BackSpace {35 38} BackSpace {35 39} BackSpace {35 40} Meta_h {35 41} Meta_H {35 42} Meta_h {35 43} Meta_H {35 44} Meta_BackSpace {35 45} Meta_BackSpace {35 46} Meta_BackSpace {35 47} Meta_BackSpace {35 48} h {35 49} H {35 50} h {35 51} H {35 52} BackSpace {35 53} BackSpace {35 54} BackSpace {35 55} BackSpace {35 56} Meta_h {35 57} Meta_H {35 58} Meta_h {35 59} Meta_H {35 60} Meta_BackSpace {35 61} Meta_BackSpace {35 62} Meta_BackSpace {35 63} Meta_BackSpace {35 64} H {35 65} h {35 66} H {35 67} h {35 68} BackSpace {35 69} BackSpace {35 70} BackSpace {35 71} BackSpace {35 72} Meta_h {35 73} Meta_H {35 74} Meta_h {35 75} Meta_H {35 76} Meta_BackSpace {35 77} Meta_BackSpace {35 78} Meta_BackSpace {35 79} Meta_BackSpace {35 80} H {35 81} h {35 82} H {35 83} h {35 84} BackSpace {35 85} BackSpace {35 86} BackSpace {35 87} BackSpace {35 88} Meta_h {35 89} Meta_H {35 90} Meta_h {35 91} Meta_H {35 92} Meta_BackSpace {35 93} Meta_BackSpace {35 94} Meta_BackSpace {35 95} Meta_BackSpace {35 96} H {35 97} h {35 98} H {35 99} h {35 100} BackSpace {35 101} BackSpace {35 102} BackSpace {35 103} BackSpace {35 104} Meta_h {35 105} Meta_H {35 106} Meta_h {35 107} Meta_H {35 108} Meta_BackSpace {35 109} Meta_BackSpace {35 110} Meta_BackSpace {35 111} Meta_BackSpace {35 112} H {35 113} h {35 114} H {35 115} h {35 116} BackSpace {35 117} BackSpace {35 118} BackSpace {35 119} BackSpace {35 120} Meta_h {35 121} Meta_H {35 122} Meta_h {35 123} Meta_H {35 124} Meta_BackSpace {35 125} Meta_BackSpace {35 126} Meta_BackSpace {35 127} Meta_BackSpace {36 0} j {36 1} J {36 2} j {36 3} J {36 4} Linefeed {36 5} Linefeed {36 6} Linefeed {36 7} Linefeed {36 8} Meta_j {36 9} Meta_J {36 10} Meta_j {36 11} Meta_J {36 12} Meta_Linefeed {36 13} Meta_Linefeed {36 14} Meta_Linefeed {36 15} Meta_Linefeed {36 16} j {36 17} J {36 18} j {36 19} J {36 20} Linefeed {36 21} Linefeed {36 22} Linefeed {36 23} Linefeed {36 24} Meta_j {36 25} Meta_J {36 26} Meta_j {36 27} Meta_J {36 28} Meta_Linefeed {36 29} Meta_Linefeed {36 30} Meta_Linefeed {36 31} Meta_Linefeed {36 32} j {36 33} J {36 34} j {36 35} J {36 36} Linefeed {36 37} Linefeed {36 38} Linefeed {36 39} Linefeed {36 40} Meta_j {36 41} Meta_J {36 42} Meta_j {36 43} Meta_J {36 44} Meta_Linefeed {36 45} Meta_Linefeed {36 46} Meta_Linefeed {36 47} Meta_Linefeed {36 48} j {36 49} J {36 50} j {36 51} J {36 52} Linefeed {36 53} Linefeed {36 54} Linefeed {36 55} Linefeed {36 56} Meta_j {36 57} Meta_J {36 58} Meta_j {36 59} Meta_J {36 60} Meta_Linefeed {36 61} Meta_Linefeed {36 62} Meta_Linefeed {36 63} Meta_Linefeed {36 64} J {36 65} j {36 66} J {36 67} j {36 68} Linefeed {36 69} Linefeed {36 70} Linefeed {36 71} Linefeed {36 72} Meta_j {36 73} Meta_J {36 74} Meta_j {36 75} Meta_J {36 76} Meta_Linefeed {36 77} Meta_Linefeed {36 78} Meta_Linefeed {36 79} Meta_Linefeed {36 80} J {36 81} j {36 82} J {36 83} j {36 84} Linefeed {36 85} Linefeed {36 86} Linefeed {36 87} Linefeed {36 88} Meta_j {36 89} Meta_J {36 90} Meta_j {36 91} Meta_J {36 92} Meta_Linefeed {36 93} Meta_Linefeed {36 94} Meta_Linefeed {36 95} Meta_Linefeed {36 96} J {36 97} j {36 98} J {36 99} j {36 100} Linefeed {36 101} Linefeed {36 102} Linefeed {36 103} Linefeed {36 104} Meta_j {36 105} Meta_J {36 106} Meta_j {36 107} Meta_J {36 108} Meta_Linefeed {36 109} Meta_Linefeed {36 110} Meta_Linefeed {36 111} Meta_Linefeed {36 112} J {36 113} j {36 114} J {36 115} j {36 116} Linefeed {36 117} Linefeed {36 118} Linefeed {36 119} Linefeed {36 120} Meta_j {36 121} Meta_J {36 122} Meta_j {36 123} Meta_J {36 124} Meta_Linefeed {36 125} Meta_Linefeed {36 126} Meta_Linefeed {36 127} Meta_Linefeed {37 0} k {37 1} K {37 2} k {37 3} K {37 4} Control_k {37 5} Control_k {37 6} Control_k {37 7} Control_k {37 8} Meta_k {37 9} Meta_K {37 10} Meta_k {37 11} Meta_K {37 12} Meta_Control_k {37 13} Meta_Control_k {37 14} Meta_Control_k {37 15} Meta_Control_k {37 16} k {37 17} K {37 18} k {37 19} K {37 20} Control_k {37 21} Control_k {37 22} Control_k {37 23} Control_k {37 24} Meta_k {37 25} Meta_K {37 26} Meta_k {37 27} Meta_K {37 28} Meta_Control_k {37 29} Meta_Control_k {37 30} Meta_Control_k {37 31} Meta_Control_k {37 32} k {37 33} K {37 34} k {37 35} K {37 36} Control_k {37 37} Control_k {37 38} Control_k {37 39} Control_k {37 40} Meta_k {37 41} Meta_K {37 42} Meta_k {37 43} Meta_K {37 44} Meta_Control_k {37 45} Meta_Control_k {37 46} Meta_Control_k {37 47} Meta_Control_k {37 48} k {37 49} K {37 50} k {37 51} K {37 52} Control_k {37 53} Control_k {37 54} Control_k {37 55} Control_k {37 56} Meta_k {37 57} Meta_K {37 58} Meta_k {37 59} Meta_K {37 60} Meta_Control_k {37 61} Meta_Control_k {37 62} Meta_Control_k {37 63} Meta_Control_k {37 64} K {37 65} k {37 66} K {37 67} k {37 68} Control_k {37 69} Control_k {37 70} Control_k {37 71} Control_k {37 72} Meta_k {37 73} Meta_K {37 74} Meta_k {37 75} Meta_K {37 76} Meta_Control_k {37 77} Meta_Control_k {37 78} Meta_Control_k {37 79} Meta_Control_k {37 80} K {37 81} k {37 82} K {37 83} k {37 84} Control_k {37 85} Control_k {37 86} Control_k {37 87} Control_k {37 88} Meta_k {37 89} Meta_K {37 90} Meta_k {37 91} Meta_K {37 92} Meta_Control_k {37 93} Meta_Control_k {37 94} Meta_Control_k {37 95} Meta_Control_k {37 96} K {37 97} k {37 98} K {37 99} k {37 100} Control_k {37 101} Control_k {37 102} Control_k {37 103} Control_k {37 104} Meta_k {37 105} Meta_K {37 106} Meta_k {37 107} Meta_K {37 108} Meta_Control_k {37 109} Meta_Control_k {37 110} Meta_Control_k {37 111} Meta_Control_k {37 112} K {37 113} k {37 114} K {37 115} k {37 116} Control_k {37 117} Control_k {37 118} Control_k {37 119} Control_k {37 120} Meta_k {37 121} Meta_K {37 122} Meta_k {37 123} Meta_K {37 124} Meta_Control_k {37 125} Meta_Control_k {37 126} Meta_Control_k {37 127} Meta_Control_k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} Control_l {38 5} Control_l {38 6} Control_l {38 7} Control_l {38 8} Meta_l {38 9} Meta_L {38 10} Meta_l {38 11} Meta_L {38 12} Meta_Control_l {38 13} Meta_Control_l {38 14} Meta_Control_l {38 15} Meta_Control_l {38 16} l {38 17} L {38 18} l {38 19} L {38 20} Control_l {38 21} Control_l {38 22} Control_l {38 23} Control_l {38 24} Meta_l {38 25} Meta_L {38 26} Meta_l {38 27} Meta_L {38 28} Meta_Control_l {38 29} Meta_Control_l {38 30} Meta_Control_l {38 31} Meta_Control_l {38 32} l {38 33} L {38 34} l {38 35} L {38 36} Control_l {38 37} Control_l {38 38} Control_l {38 39} Control_l {38 40} Meta_l {38 41} Meta_L {38 42} Meta_l {38 43} Meta_L {38 44} Meta_Control_l {38 45} Meta_Control_l {38 46} Meta_Control_l {38 47} Meta_Control_l {38 48} l {38 49} L {38 50} l {38 51} L {38 52} Control_l {38 53} Control_l {38 54} Control_l {38 55} Control_l {38 56} Meta_l {38 57} Meta_L {38 58} Meta_l {38 59} Meta_L {38 60} Meta_Control_l {38 61} Meta_Control_l {38 62} Meta_Control_l {38 63} Meta_Control_l {38 64} L {38 65} l {38 66} L {38 67} l {38 68} Control_l {38 69} Control_l {38 70} Control_l {38 71} Control_l {38 72} Meta_l {38 73} Meta_L {38 74} Meta_l {38 75} Meta_L {38 76} Meta_Control_l {38 77} Meta_Control_l {38 78} Meta_Control_l {38 79} Meta_Control_l {38 80} L {38 81} l {38 82} L {38 83} l {38 84} Control_l {38 85} Control_l {38 86} Control_l {38 87} Control_l {38 88} Meta_l {38 89} Meta_L {38 90} Meta_l {38 91} Meta_L {38 92} Meta_Control_l {38 93} Meta_Control_l {38 94} Meta_Control_l {38 95} Meta_Control_l {38 96} L {38 97} l {38 98} L {38 99} l {38 100} Control_l {38 101} Control_l {38 102} Control_l {38 103} Control_l {38 104} Meta_l {38 105} Meta_L {38 106} Meta_l {38 107} Meta_L {38 108} Meta_Control_l {38 109} Meta_Control_l {38 110} Meta_Control_l {38 111} Meta_Control_l {38 112} L {38 113} l {38 114} L {38 115} l {38 116} Control_l {38 117} Control_l {38 118} Control_l {38 119} Control_l {38 120} Meta_l {38 121} Meta_L {38 122} Meta_l {38 123} Meta_L {38 124} Meta_Control_l {38 125} Meta_Control_l {38 126} Meta_Control_l {38 127} Meta_Control_l {39 0} semicolon {39 1} colon {39 2} semicolon {39 3} colon {39 4} semicolon {39 5} colon {39 6} semicolon {39 7} colon {39 8} Meta_semicolon {39 9} Meta_colon {39 10} Meta_semicolon {39 11} Meta_colon {39 12} Meta_semicolon {39 13} Meta_colon {39 14} Meta_semicolon {39 15} Meta_colon {39 16} semicolon {39 17} colon {39 18} semicolon {39 19} colon {39 20} semicolon {39 21} colon {39 22} semicolon {39 23} colon {39 24} Meta_semicolon {39 25} Meta_colon {39 26} Meta_semicolon {39 27} Meta_colon {39 28} Meta_semicolon {39 29} Meta_colon {39 30} Meta_semicolon {39 31} Meta_colon {39 32} semicolon {39 33} colon {39 34} semicolon {39 35} colon {39 36} semicolon {39 37} colon {39 38} semicolon {39 39} colon {39 40} Meta_semicolon {39 41} Meta_colon {39 42} Meta_semicolon {39 43} Meta_colon {39 44} Meta_semicolon {39 45} Meta_colon {39 46} Meta_semicolon {39 47} Meta_colon {39 48} semicolon {39 49} colon {39 50} semicolon {39 51} colon {39 52} semicolon {39 53} colon {39 54} semicolon {39 55} colon {39 56} Meta_semicolon {39 57} Meta_colon {39 58} Meta_semicolon {39 59} Meta_colon {39 60} Meta_semicolon {39 61} Meta_colon {39 62} Meta_semicolon {39 63} Meta_colon {39 64} semicolon {39 65} colon {39 66} semicolon {39 67} colon {39 68} semicolon {39 69} colon {39 70} semicolon {39 71} colon {39 72} Meta_semicolon {39 73} Meta_colon {39 74} Meta_semicolon {39 75} Meta_colon {39 76} Meta_semicolon {39 77} Meta_colon {39 78} Meta_semicolon {39 79} Meta_colon {39 80} semicolon {39 81} colon {39 82} semicolon {39 83} colon {39 84} semicolon {39 85} colon {39 86} semicolon {39 87} colon {39 88} Meta_semicolon {39 89} Meta_colon {39 90} Meta_semicolon {39 91} Meta_colon {39 92} Meta_semicolon {39 93} Meta_colon {39 94} Meta_semicolon {39 95} Meta_colon {39 96} semicolon {39 97} colon {39 98} semicolon {39 99} colon {39 100} semicolon {39 101} colon {39 102} semicolon {39 103} colon {39 104} Meta_semicolon {39 105} Meta_colon {39 106} Meta_semicolon {39 107} Meta_colon {39 108} Meta_semicolon {39 109} Meta_colon {39 110} Meta_semicolon {39 111} Meta_colon {39 112} semicolon {39 113} colon {39 114} semicolon {39 115} colon {39 116} semicolon {39 117} colon {39 118} semicolon {39 119} colon {39 120} Meta_semicolon {39 121} Meta_colon {39 122} Meta_semicolon {39 123} Meta_colon {39 124} Meta_semicolon {39 125} Meta_colon {39 126} Meta_semicolon {39 127} Meta_colon {40 0} apostrophe {40 1} quotedbl {40 2} apostrophe {40 3} quotedbl {40 4} apostrophe {40 5} quotedbl {40 6} apostrophe {40 7} quotedbl {40 8} Meta_apostrophe {40 9} Meta_quotedbl {40 10} Meta_apostrophe {40 11} Meta_quotedbl {40 12} Meta_apostrophe {40 13} Meta_quotedbl {40 14} Meta_apostrophe {40 15} Meta_quotedbl {40 16} apostrophe {40 17} quotedbl {40 18} apostrophe {40 19} quotedbl {40 20} apostrophe {40 21} quotedbl {40 22} apostrophe {40 23} quotedbl {40 24} Meta_apostrophe {40 25} Meta_quotedbl {40 26} Meta_apostrophe {40 27} Meta_quotedbl {40 28} Meta_apostrophe {40 29} Meta_quotedbl {40 30} Meta_apostrophe {40 31} Meta_quotedbl {40 32} apostrophe {40 33} quotedbl {40 34} apostrophe {40 35} quotedbl {40 36} apostrophe {40 37} quotedbl {40 38} apostrophe {40 39} quotedbl {40 40} Meta_apostrophe {40 41} Meta_quotedbl {40 42} Meta_apostrophe {40 43} Meta_quotedbl {40 44} Meta_apostrophe {40 45} Meta_quotedbl {40 46} Meta_apostrophe {40 47} Meta_quotedbl {40 48} apostrophe {40 49} quotedbl {40 50} apostrophe {40 51} quotedbl {40 52} apostrophe {40 53} quotedbl {40 54} apostrophe {40 55} quotedbl {40 56} Meta_apostrophe {40 57} Meta_quotedbl {40 58} Meta_apostrophe {40 59} Meta_quotedbl {40 60} Meta_apostrophe {40 61} Meta_quotedbl {40 62} Meta_apostrophe {40 63} Meta_quotedbl {40 64} apostrophe {40 65} quotedbl {40 66} apostrophe {40 67} quotedbl {40 68} apostrophe {40 69} quotedbl {40 70} apostrophe {40 71} quotedbl {40 72} Meta_apostrophe {40 73} Meta_quotedbl {40 74} Meta_apostrophe {40 75} Meta_quotedbl {40 76} Meta_apostrophe {40 77} Meta_quotedbl {40 78} Meta_apostrophe {40 79} Meta_quotedbl {40 80} apostrophe {40 81} quotedbl {40 82} apostrophe {40 83} quotedbl {40 84} apostrophe {40 85} quotedbl {40 86} apostrophe {40 87} quotedbl {40 88} Meta_apostrophe {40 89} Meta_quotedbl {40 90} Meta_apostrophe {40 91} Meta_quotedbl {40 92} Meta_apostrophe {40 93} Meta_quotedbl {40 94} Meta_apostrophe {40 95} Meta_quotedbl {40 96} apostrophe {40 97} quotedbl {40 98} apostrophe {40 99} quotedbl {40 100} apostrophe {40 101} quotedbl {40 102} apostrophe {40 103} quotedbl {40 104} Meta_apostrophe {40 105} Meta_quotedbl {40 106} Meta_apostrophe {40 107} Meta_quotedbl {40 108} Meta_apostrophe {40 109} Meta_quotedbl {40 110} Meta_apostrophe {40 111} Meta_quotedbl {40 112} apostrophe {40 113} quotedbl {40 114} apostrophe {40 115} quotedbl {40 116} apostrophe {40 117} quotedbl {40 118} apostrophe {40 119} quotedbl {40 120} Meta_apostrophe {40 121} Meta_quotedbl {40 122} Meta_apostrophe {40 123} Meta_quotedbl {40 124} Meta_apostrophe {40 125} Meta_quotedbl {40 126} Meta_apostrophe {40 127} Meta_quotedbl {41 0} grave {41 1} asciitilde {41 2} grave {41 3} asciitilde {41 4} nul {41 5} Control_asciicircum {41 6} nul {41 7} Control_asciicircum {41 8} Meta_grave {41 9} Meta_asciitilde {41 10} Meta_grave {41 11} Meta_asciitilde {41 12} Meta_nul {41 13} Meta_Control_asciicircum {41 14} Meta_nul {41 15} Meta_Control_asciicircum {41 16} grave {41 17} asciitilde {41 18} grave {41 19} asciitilde {41 20} nul {41 21} Control_asciicircum {41 22} nul {41 23} Control_asciicircum {41 24} Meta_grave {41 25} Meta_asciitilde {41 26} Meta_grave {41 27} Meta_asciitilde {41 28} Meta_nul {41 29} Meta_Control_asciicircum {41 30} Meta_nul {41 31} Meta_Control_asciicircum {41 32} grave {41 33} asciitilde {41 34} grave {41 35} asciitilde {41 36} nul {41 37} Control_asciicircum {41 38} nul {41 39} Control_asciicircum {41 40} Meta_grave {41 41} Meta_asciitilde {41 42} Meta_grave {41 43} Meta_asciitilde {41 44} Meta_nul {41 45} Meta_Control_asciicircum {41 46} Meta_nul {41 47} Meta_Control_asciicircum {41 48} grave {41 49} asciitilde {41 50} grave {41 51} asciitilde {41 52} nul {41 53} Control_asciicircum {41 54} nul {41 55} Control_asciicircum {41 56} Meta_grave {41 57} Meta_asciitilde {41 58} Meta_grave {41 59} Meta_asciitilde {41 60} Meta_nul {41 61} Meta_Control_asciicircum {41 62} Meta_nul {41 63} Meta_Control_asciicircum {41 64} grave {41 65} asciitilde {41 66} grave {41 67} asciitilde {41 68} nul {41 69} Control_asciicircum {41 70} nul {41 71} Control_asciicircum {41 72} Meta_grave {41 73} Meta_asciitilde {41 74} Meta_grave {41 75} Meta_asciitilde {41 76} Meta_nul {41 77} Meta_Control_asciicircum {41 78} Meta_nul {41 79} Meta_Control_asciicircum {41 80} grave {41 81} asciitilde {41 82} grave {41 83} asciitilde {41 84} nul {41 85} Control_asciicircum {41 86} nul {41 87} Control_asciicircum {41 88} Meta_grave {41 89} Meta_asciitilde {41 90} Meta_grave {41 91} Meta_asciitilde {41 92} Meta_nul {41 93} Meta_Control_asciicircum {41 94} Meta_nul {41 95} Meta_Control_asciicircum {41 96} grave {41 97} asciitilde {41 98} grave {41 99} asciitilde {41 100} nul {41 101} Control_asciicircum {41 102} nul {41 103} Control_asciicircum {41 104} Meta_grave {41 105} Meta_asciitilde {41 106} Meta_grave {41 107} Meta_asciitilde {41 108} Meta_nul {41 109} Meta_Control_asciicircum {41 110} Meta_nul {41 111} Meta_Control_asciicircum {41 112} grave {41 113} asciitilde {41 114} grave {41 115} asciitilde {41 116} nul {41 117} Control_asciicircum {41 118} nul {41 119} Control_asciicircum {41 120} Meta_grave {41 121} Meta_asciitilde {41 122} Meta_grave {41 123} Meta_asciitilde {41 124} Meta_nul {41 125} Meta_Control_asciicircum {41 126} Meta_nul {41 127} Meta_Control_asciicircum {42 0} Shift {42 1} Shift {42 2} Shift {42 3} Shift {42 4} Shift {42 5} Shift {42 6} Shift {42 7} Shift {42 8} Shift {42 9} Shift {42 10} Shift {42 11} Shift {42 12} Shift {42 13} Shift {42 14} Shift {42 15} Shift {42 16} Shift {42 17} Shift {42 18} Shift {42 19} Shift {42 20} Shift {42 21} Shift {42 22} Shift {42 23} Shift {42 24} Shift {42 25} Shift {42 26} Shift {42 27} Shift {42 28} Shift {42 29} Shift {42 30} Shift {42 31} Shift {42 32} Shift {42 33} Shift {42 34} Shift {42 35} Shift {42 36} Shift {42 37} Shift {42 38} Shift {42 39} Shift {42 40} Shift {42 41} Shift {42 42} Shift {42 43} Shift {42 44} Shift {42 45} Shift {42 46} Shift {42 47} Shift {42 48} Shift {42 49} Shift {42 50} Shift {42 51} Shift {42 52} Shift {42 53} Shift {42 54} Shift {42 55} Shift {42 56} Shift {42 57} Shift {42 58} Shift {42 59} Shift {42 60} Shift {42 61} Shift {42 62} Shift {42 63} Shift {42 64} Shift {42 65} Shift {42 66} Shift {42 67} Shift {42 68} Shift {42 69} Shift {42 70} Shift {42 71} Shift {42 72} Shift {42 73} Shift {42 74} Shift {42 75} Shift {42 76} Shift {42 77} Shift {42 78} Shift {42 79} Shift {42 80} Shift {42 81} Shift {42 82} Shift {42 83} Shift {42 84} Shift {42 85} Shift {42 86} Shift {42 87} Shift {42 88} Shift {42 89} Shift {42 90} Shift {42 91} Shift {42 92} Shift {42 93} Shift {42 94} Shift {42 95} Shift {42 96} Shift {42 97} Shift {42 98} Shift {42 99} Shift {42 100} Shift {42 101} Shift {42 102} Shift {42 103} Shift {42 104} Shift {42 105} Shift {42 106} Shift {42 107} Shift {42 108} Shift {42 109} Shift {42 110} Shift {42 111} Shift {42 112} Shift {42 113} Shift {42 114} Shift {42 115} Shift {42 116} Shift {42 117} Shift {42 118} Shift {42 119} Shift {42 120} Shift {42 121} Shift {42 122} Shift {42 123} Shift {42 124} Shift {42 125} Shift {42 126} Shift {42 127} Shift {43 0} backslash {43 1} bar {43 2} backslash {43 3} bar {43 4} Control_backslash {43 5} Control_backslash {43 6} Control_backslash {43 7} Control_backslash {43 8} Meta_backslash {43 9} Meta_bar {43 10} Meta_backslash {43 11} Meta_bar {43 12} Meta_Control_backslash {43 13} Meta_Control_backslash {43 14} Meta_Control_backslash {43 15} Meta_Control_backslash {43 16} backslash {43 17} bar {43 18} backslash {43 19} bar {43 20} Control_backslash {43 21} Control_backslash {43 22} Control_backslash {43 23} Control_backslash {43 24} Meta_backslash {43 25} Meta_bar {43 26} Meta_backslash {43 27} Meta_bar {43 28} Meta_Control_backslash {43 29} Meta_Control_backslash {43 30} Meta_Control_backslash {43 31} Meta_Control_backslash {43 32} backslash {43 33} bar {43 34} backslash {43 35} bar {43 36} Control_backslash {43 37} Control_backslash {43 38} Control_backslash {43 39} Control_backslash {43 40} Meta_backslash {43 41} Meta_bar {43 42} Meta_backslash {43 43} Meta_bar {43 44} Meta_Control_backslash {43 45} Meta_Control_backslash {43 46} Meta_Control_backslash {43 47} Meta_Control_backslash {43 48} backslash {43 49} bar {43 50} backslash {43 51} bar {43 52} Control_backslash {43 53} Control_backslash {43 54} Control_backslash {43 55} Control_backslash {43 56} Meta_backslash {43 57} Meta_bar {43 58} Meta_backslash {43 59} Meta_bar {43 60} Meta_Control_backslash {43 61} Meta_Control_backslash {43 62} Meta_Control_backslash {43 63} Meta_Control_backslash {43 64} backslash {43 65} bar {43 66} backslash {43 67} bar {43 68} Control_backslash {43 69} Control_backslash {43 70} Control_backslash {43 71} Control_backslash {43 72} Meta_backslash {43 73} Meta_bar {43 74} Meta_backslash {43 75} Meta_bar {43 76} Meta_Control_backslash {43 77} Meta_Control_backslash {43 78} Meta_Control_backslash {43 79} Meta_Control_backslash {43 80} backslash {43 81} bar {43 82} backslash {43 83} bar {43 84} Control_backslash {43 85} Control_backslash {43 86} Control_backslash {43 87} Control_backslash {43 88} Meta_backslash {43 89} Meta_bar {43 90} Meta_backslash {43 91} Meta_bar {43 92} Meta_Control_backslash {43 93} Meta_Control_backslash {43 94} Meta_Control_backslash {43 95} Meta_Control_backslash {43 96} backslash {43 97} bar {43 98} backslash {43 99} bar {43 100} Control_backslash {43 101} Control_backslash {43 102} Control_backslash {43 103} Control_backslash {43 104} Meta_backslash {43 105} Meta_bar {43 106} Meta_backslash {43 107} Meta_bar {43 108} Meta_Control_backslash {43 109} Meta_Control_backslash {43 110} Meta_Control_backslash {43 111} Meta_Control_backslash {43 112} backslash {43 113} bar {43 114} backslash {43 115} bar {43 116} Control_backslash {43 117} Control_backslash {43 118} Control_backslash {43 119} Control_backslash {43 120} Meta_backslash {43 121} Meta_bar {43 122} Meta_backslash {43 123} Meta_bar {43 124} Meta_Control_backslash {43 125} Meta_Control_backslash {43 126} Meta_Control_backslash {43 127} Meta_Control_backslash {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} Control_z {44 5} Control_z {44 6} Control_z {44 7} Control_z {44 8} Meta_z {44 9} Meta_Z {44 10} Meta_z {44 11} Meta_Z {44 12} Meta_Control_z {44 13} Meta_Control_z {44 14} Meta_Control_z {44 15} Meta_Control_z {44 16} z {44 17} Z {44 18} z {44 19} Z {44 20} Control_z {44 21} Control_z {44 22} Control_z {44 23} Control_z {44 24} Meta_z {44 25} Meta_Z {44 26} Meta_z {44 27} Meta_Z {44 28} Meta_Control_z {44 29} Meta_Control_z {44 30} Meta_Control_z {44 31} Meta_Control_z {44 32} z {44 33} Z {44 34} z {44 35} Z {44 36} Control_z {44 37} Control_z {44 38} Control_z {44 39} Control_z {44 40} Meta_z {44 41} Meta_Z {44 42} Meta_z {44 43} Meta_Z {44 44} Meta_Control_z {44 45} Meta_Control_z {44 46} Meta_Control_z {44 47} Meta_Control_z {44 48} z {44 49} Z {44 50} z {44 51} Z {44 52} Control_z {44 53} Control_z {44 54} Control_z {44 55} Control_z {44 56} Meta_z {44 57} Meta_Z {44 58} Meta_z {44 59} Meta_Z {44 60} Meta_Control_z {44 61} Meta_Control_z {44 62} Meta_Control_z {44 63} Meta_Control_z {44 64} Z {44 65} z {44 66} Z {44 67} z {44 68} Control_z {44 69} Control_z {44 70} Control_z {44 71} Control_z {44 72} Meta_z {44 73} Meta_Z {44 74} Meta_z {44 75} Meta_Z {44 76} Meta_Control_z {44 77} Meta_Control_z {44 78} Meta_Control_z {44 79} Meta_Control_z {44 80} Z {44 81} z {44 82} Z {44 83} z {44 84} Control_z {44 85} Control_z {44 86} Control_z {44 87} Control_z {44 88} Meta_z {44 89} Meta_Z {44 90} Meta_z {44 91} Meta_Z {44 92} Meta_Control_z {44 93} Meta_Control_z {44 94} Meta_Control_z {44 95} Meta_Control_z {44 96} Z {44 97} z {44 98} Z {44 99} z {44 100} Control_z {44 101} Control_z {44 102} Control_z {44 103} Control_z {44 104} Meta_z {44 105} Meta_Z {44 106} Meta_z {44 107} Meta_Z {44 108} Meta_Control_z {44 109} Meta_Control_z {44 110} Meta_Control_z {44 111} Meta_Control_z {44 112} Z {44 113} z {44 114} Z {44 115} z {44 116} Control_z {44 117} Control_z {44 118} Control_z {44 119} Control_z {44 120} Meta_z {44 121} Meta_Z {44 122} Meta_z {44 123} Meta_Z {44 124} Meta_Control_z {44 125} Meta_Control_z {44 126} Meta_Control_z {44 127} Meta_Control_z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} Control_x {45 5} Control_x {45 6} Control_x {45 7} Control_x {45 8} Meta_x {45 9} Meta_X {45 10} Meta_x {45 11} Meta_X {45 12} Meta_Control_x {45 13} Meta_Control_x {45 14} Meta_Control_x {45 15} Meta_Control_x {45 16} x {45 17} X {45 18} x {45 19} X {45 20} Control_x {45 21} Control_x {45 22} Control_x {45 23} Control_x {45 24} Meta_x {45 25} Meta_X {45 26} Meta_x {45 27} Meta_X {45 28} Meta_Control_x {45 29} Meta_Control_x {45 30} Meta_Control_x {45 31} Meta_Control_x {45 32} x {45 33} X {45 34} x {45 35} X {45 36} Control_x {45 37} Control_x {45 38} Control_x {45 39} Control_x {45 40} Meta_x {45 41} Meta_X {45 42} Meta_x {45 43} Meta_X {45 44} Meta_Control_x {45 45} Meta_Control_x {45 46} Meta_Control_x {45 47} Meta_Control_x {45 48} x {45 49} X {45 50} x {45 51} X {45 52} Control_x {45 53} Control_x {45 54} Control_x {45 55} Control_x {45 56} Meta_x {45 57} Meta_X {45 58} Meta_x {45 59} Meta_X {45 60} Meta_Control_x {45 61} Meta_Control_x {45 62} Meta_Control_x {45 63} Meta_Control_x {45 64} X {45 65} x {45 66} X {45 67} x {45 68} Control_x {45 69} Control_x {45 70} Control_x {45 71} Control_x {45 72} Meta_x {45 73} Meta_X {45 74} Meta_x {45 75} Meta_X {45 76} Meta_Control_x {45 77} Meta_Control_x {45 78} Meta_Control_x {45 79} Meta_Control_x {45 80} X {45 81} x {45 82} X {45 83} x {45 84} Control_x {45 85} Control_x {45 86} Control_x {45 87} Control_x {45 88} Meta_x {45 89} Meta_X {45 90} Meta_x {45 91} Meta_X {45 92} Meta_Control_x {45 93} Meta_Control_x {45 94} Meta_Control_x {45 95} Meta_Control_x {45 96} X {45 97} x {45 98} X {45 99} x {45 100} Control_x {45 101} Control_x {45 102} Control_x {45 103} Control_x {45 104} Meta_x {45 105} Meta_X {45 106} Meta_x {45 107} Meta_X {45 108} Meta_Control_x {45 109} Meta_Control_x {45 110} Meta_Control_x {45 111} Meta_Control_x {45 112} X {45 113} x {45 114} X {45 115} x {45 116} Control_x {45 117} Control_x {45 118} Control_x {45 119} Control_x {45 120} Meta_x {45 121} Meta_X {45 122} Meta_x {45 123} Meta_X {45 124} Meta_Control_x {45 125} Meta_Control_x {45 126} Meta_Control_x {45 127} Meta_Control_x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} Control_c {46 5} Control_c {46 6} Control_c {46 7} Control_c {46 8} Meta_c {46 9} Meta_C {46 10} Meta_c {46 11} Meta_C {46 12} Meta_Control_c {46 13} Meta_Control_c {46 14} Meta_Control_c {46 15} Meta_Control_c {46 16} c {46 17} C {46 18} c {46 19} C {46 20} Control_c {46 21} Control_c {46 22} Control_c {46 23} Control_c {46 24} Meta_c {46 25} Meta_C {46 26} Meta_c {46 27} Meta_C {46 28} Meta_Control_c {46 29} Meta_Control_c {46 30} Meta_Control_c {46 31} Meta_Control_c {46 32} c {46 33} C {46 34} c {46 35} C {46 36} Control_c {46 37} Control_c {46 38} Control_c {46 39} Control_c {46 40} Meta_c {46 41} Meta_C {46 42} Meta_c {46 43} Meta_C {46 44} Meta_Control_c {46 45} Meta_Control_c {46 46} Meta_Control_c {46 47} Meta_Control_c {46 48} c {46 49} C {46 50} c {46 51} C {46 52} Control_c {46 53} Control_c {46 54} Control_c {46 55} Control_c {46 56} Meta_c {46 57} Meta_C {46 58} Meta_c {46 59} Meta_C {46 60} Meta_Control_c {46 61} Meta_Control_c {46 62} Meta_Control_c {46 63} Meta_Control_c {46 64} C {46 65} c {46 66} C {46 67} c {46 68} Control_c {46 69} Control_c {46 70} Control_c {46 71} Control_c {46 72} Meta_c {46 73} Meta_C {46 74} Meta_c {46 75} Meta_C {46 76} Meta_Control_c {46 77} Meta_Control_c {46 78} Meta_Control_c {46 79} Meta_Control_c {46 80} C {46 81} c {46 82} C {46 83} c {46 84} Control_c {46 85} Control_c {46 86} Control_c {46 87} Control_c {46 88} Meta_c {46 89} Meta_C {46 90} Meta_c {46 91} Meta_C {46 92} Meta_Control_c {46 93} Meta_Control_c {46 94} Meta_Control_c {46 95} Meta_Control_c {46 96} C {46 97} c {46 98} C {46 99} c {46 100} Control_c {46 101} Control_c {46 102} Control_c {46 103} Control_c {46 104} Meta_c {46 105} Meta_C {46 106} Meta_c {46 107} Meta_C {46 108} Meta_Control_c {46 109} Meta_Control_c {46 110} Meta_Control_c {46 111} Meta_Control_c {46 112} C {46 113} c {46 114} C {46 115} c {46 116} Control_c {46 117} Control_c {46 118} Control_c {46 119} Control_c {46 120} Meta_c {46 121} Meta_C {46 122} Meta_c {46 123} Meta_C {46 124} Meta_Control_c {46 125} Meta_Control_c {46 126} Meta_Control_c {46 127} Meta_Control_c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} Control_v {47 5} Control_v {47 6} Control_v {47 7} Control_v {47 8} Meta_v {47 9} Meta_V {47 10} Meta_v {47 11} Meta_V {47 12} Meta_Control_v {47 13} Meta_Control_v {47 14} Meta_Control_v {47 15} Meta_Control_v {47 16} v {47 17} V {47 18} v {47 19} V {47 20} Control_v {47 21} Control_v {47 22} Control_v {47 23} Control_v {47 24} Meta_v {47 25} Meta_V {47 26} Meta_v {47 27} Meta_V {47 28} Meta_Control_v {47 29} Meta_Control_v {47 30} Meta_Control_v {47 31} Meta_Control_v {47 32} v {47 33} V {47 34} v {47 35} V {47 36} Control_v {47 37} Control_v {47 38} Control_v {47 39} Control_v {47 40} Meta_v {47 41} Meta_V {47 42} Meta_v {47 43} Meta_V {47 44} Meta_Control_v {47 45} Meta_Control_v {47 46} Meta_Control_v {47 47} Meta_Control_v {47 48} v {47 49} V {47 50} v {47 51} V {47 52} Control_v {47 53} Control_v {47 54} Control_v {47 55} Control_v {47 56} Meta_v {47 57} Meta_V {47 58} Meta_v {47 59} Meta_V {47 60} Meta_Control_v {47 61} Meta_Control_v {47 62} Meta_Control_v {47 63} Meta_Control_v {47 64} V {47 65} v {47 66} V {47 67} v {47 68} Control_v {47 69} Control_v {47 70} Control_v {47 71} Control_v {47 72} Meta_v {47 73} Meta_V {47 74} Meta_v {47 75} Meta_V {47 76} Meta_Control_v {47 77} Meta_Control_v {47 78} Meta_Control_v {47 79} Meta_Control_v {47 80} V {47 81} v {47 82} V {47 83} v {47 84} Control_v {47 85} Control_v {47 86} Control_v {47 87} Control_v {47 88} Meta_v {47 89} Meta_V {47 90} Meta_v {47 91} Meta_V {47 92} Meta_Control_v {47 93} Meta_Control_v {47 94} Meta_Control_v {47 95} Meta_Control_v {47 96} V {47 97} v {47 98} V {47 99} v {47 100} Control_v {47 101} Control_v {47 102} Control_v {47 103} Control_v {47 104} Meta_v {47 105} Meta_V {47 106} Meta_v {47 107} Meta_V {47 108} Meta_Control_v {47 109} Meta_Control_v {47 110} Meta_Control_v {47 111} Meta_Control_v {47 112} V {47 113} v {47 114} V {47 115} v {47 116} Control_v {47 117} Control_v {47 118} Control_v {47 119} Control_v {47 120} Meta_v {47 121} Meta_V {47 122} Meta_v {47 123} Meta_V {47 124} Meta_Control_v {47 125} Meta_Control_v {47 126} Meta_Control_v {47 127} Meta_Control_v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} Control_b {48 5} Control_b {48 6} Control_b {48 7} Control_b {48 8} Meta_b {48 9} Meta_B {48 10} Meta_b {48 11} Meta_B {48 12} Meta_Control_b {48 13} Meta_Control_b {48 14} Meta_Control_b {48 15} Meta_Control_b {48 16} b {48 17} B {48 18} b {48 19} B {48 20} Control_b {48 21} Control_b {48 22} Control_b {48 23} Control_b {48 24} Meta_b {48 25} Meta_B {48 26} Meta_b {48 27} Meta_B {48 28} Meta_Control_b {48 29} Meta_Control_b {48 30} Meta_Control_b {48 31} Meta_Control_b {48 32} b {48 33} B {48 34} b {48 35} B {48 36} Control_b {48 37} Control_b {48 38} Control_b {48 39} Control_b {48 40} Meta_b {48 41} Meta_B {48 42} Meta_b {48 43} Meta_B {48 44} Meta_Control_b {48 45} Meta_Control_b {48 46} Meta_Control_b {48 47} Meta_Control_b {48 48} b {48 49} B {48 50} b {48 51} B {48 52} Control_b {48 53} Control_b {48 54} Control_b {48 55} Control_b {48 56} Meta_b {48 57} Meta_B {48 58} Meta_b {48 59} Meta_B {48 60} Meta_Control_b {48 61} Meta_Control_b {48 62} Meta_Control_b {48 63} Meta_Control_b {48 64} B {48 65} b {48 66} B {48 67} b {48 68} Control_b {48 69} Control_b {48 70} Control_b {48 71} Control_b {48 72} Meta_b {48 73} Meta_B {48 74} Meta_b {48 75} Meta_B {48 76} Meta_Control_b {48 77} Meta_Control_b {48 78} Meta_Control_b {48 79} Meta_Control_b {48 80} B {48 81} b {48 82} B {48 83} b {48 84} Control_b {48 85} Control_b {48 86} Control_b {48 87} Control_b {48 88} Meta_b {48 89} Meta_B {48 90} Meta_b {48 91} Meta_B {48 92} Meta_Control_b {48 93} Meta_Control_b {48 94} Meta_Control_b {48 95} Meta_Control_b {48 96} B {48 97} b {48 98} B {48 99} b {48 100} Control_b {48 101} Control_b {48 102} Control_b {48 103} Control_b {48 104} Meta_b {48 105} Meta_B {48 106} Meta_b {48 107} Meta_B {48 108} Meta_Control_b {48 109} Meta_Control_b {48 110} Meta_Control_b {48 111} Meta_Control_b {48 112} B {48 113} b {48 114} B {48 115} b {48 116} Control_b {48 117} Control_b {48 118} Control_b {48 119} Control_b {48 120} Meta_b {48 121} Meta_B {48 122} Meta_b {48 123} Meta_B {48 124} Meta_Control_b {48 125} Meta_Control_b {48 126} Meta_Control_b {48 127} Meta_Control_b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} Control_n {49 5} Control_n {49 6} Control_n {49 7} Control_n {49 8} Meta_n {49 9} Meta_N {49 10} Meta_n {49 11} Meta_N {49 12} Meta_Control_n {49 13} Meta_Control_n {49 14} Meta_Control_n {49 15} Meta_Control_n {49 16} n {49 17} N {49 18} n {49 19} N {49 20} Control_n {49 21} Control_n {49 22} Control_n {49 23} Control_n {49 24} Meta_n {49 25} Meta_N {49 26} Meta_n {49 27} Meta_N {49 28} Meta_Control_n {49 29} Meta_Control_n {49 30} Meta_Control_n {49 31} Meta_Control_n {49 32} n {49 33} N {49 34} n {49 35} N {49 36} Control_n {49 37} Control_n {49 38} Control_n {49 39} Control_n {49 40} Meta_n {49 41} Meta_N {49 42} Meta_n {49 43} Meta_N {49 44} Meta_Control_n {49 45} Meta_Control_n {49 46} Meta_Control_n {49 47} Meta_Control_n {49 48} n {49 49} N {49 50} n {49 51} N {49 52} Control_n {49 53} Control_n {49 54} Control_n {49 55} Control_n {49 56} Meta_n {49 57} Meta_N {49 58} Meta_n {49 59} Meta_N {49 60} Meta_Control_n {49 61} Meta_Control_n {49 62} Meta_Control_n {49 63} Meta_Control_n {49 64} N {49 65} n {49 66} N {49 67} n {49 68} Control_n {49 69} Control_n {49 70} Control_n {49 71} Control_n {49 72} Meta_n {49 73} Meta_N {49 74} Meta_n {49 75} Meta_N {49 76} Meta_Control_n {49 77} Meta_Control_n {49 78} Meta_Control_n {49 79} Meta_Control_n {49 80} N {49 81} n {49 82} N {49 83} n {49 84} Control_n {49 85} Control_n {49 86} Control_n {49 87} Control_n {49 88} Meta_n {49 89} Meta_N {49 90} Meta_n {49 91} Meta_N {49 92} Meta_Control_n {49 93} Meta_Control_n {49 94} Meta_Control_n {49 95} Meta_Control_n {49 96} N {49 97} n {49 98} N {49 99} n {49 100} Control_n {49 101} Control_n {49 102} Control_n {49 103} Control_n {49 104} Meta_n {49 105} Meta_N {49 106} Meta_n {49 107} Meta_N {49 108} Meta_Control_n {49 109} Meta_Control_n {49 110} Meta_Control_n {49 111} Meta_Control_n {49 112} N {49 113} n {49 114} N {49 115} n {49 116} Control_n {49 117} Control_n {49 118} Control_n {49 119} Control_n {49 120} Meta_n {49 121} Meta_N {49 122} Meta_n {49 123} Meta_N {49 124} Meta_Control_n {49 125} Meta_Control_n {49 126} Meta_Control_n {49 127} Meta_Control_n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} Return {50 5} Return {50 6} Return {50 7} Return {50 8} Meta_m {50 9} Meta_M {50 10} Meta_m {50 11} Meta_M {50 12} Meta_Control_m {50 13} Meta_Control_m {50 14} Meta_Control_m {50 15} Meta_Control_m {50 16} m {50 17} M {50 18} m {50 19} M {50 20} Return {50 21} Return {50 22} Return {50 23} Return {50 24} Meta_m {50 25} Meta_M {50 26} Meta_m {50 27} Meta_M {50 28} Meta_Control_m {50 29} Meta_Control_m {50 30} Meta_Control_m {50 31} Meta_Control_m {50 32} m {50 33} M {50 34} m {50 35} M {50 36} Return {50 37} Return {50 38} Return {50 39} Return {50 40} Meta_m {50 41} Meta_M {50 42} Meta_m {50 43} Meta_M {50 44} Meta_Control_m {50 45} Meta_Control_m {50 46} Meta_Control_m {50 47} Meta_Control_m {50 48} m {50 49} M {50 50} m {50 51} M {50 52} Return {50 53} Return {50 54} Return {50 55} Return {50 56} Meta_m {50 57} Meta_M {50 58} Meta_m {50 59} Meta_M {50 60} Meta_Control_m {50 61} Meta_Control_m {50 62} Meta_Control_m {50 63} Meta_Control_m {50 64} M {50 65} m {50 66} M {50 67} m {50 68} Return {50 69} Return {50 70} Return {50 71} Return {50 72} Meta_m {50 73} Meta_M {50 74} Meta_m {50 75} Meta_M {50 76} Meta_Control_m {50 77} Meta_Control_m {50 78} Meta_Control_m {50 79} Meta_Control_m {50 80} M {50 81} m {50 82} M {50 83} m {50 84} Return {50 85} Return {50 86} Return {50 87} Return {50 88} Meta_m {50 89} Meta_M {50 90} Meta_m {50 91} Meta_M {50 92} Meta_Control_m {50 93} Meta_Control_m {50 94} Meta_Control_m {50 95} Meta_Control_m {50 96} M {50 97} m {50 98} M {50 99} m {50 100} Return {50 101} Return {50 102} Return {50 103} Return {50 104} Meta_m {50 105} Meta_M {50 106} Meta_m {50 107} Meta_M {50 108} Meta_Control_m {50 109} Meta_Control_m {50 110} Meta_Control_m {50 111} Meta_Control_m {50 112} M {50 113} m {50 114} M {50 115} m {50 116} Return {50 117} Return {50 118} Return {50 119} Return {50 120} Meta_m {50 121} Meta_M {50 122} Meta_m {50 123} Meta_M {50 124} Meta_Control_m {50 125} Meta_Control_m {50 126} Meta_Control_m {50 127} Meta_Control_m {51 0} comma {51 1} less {51 2} comma {51 3} less {51 4} comma {51 5} less {51 6} comma {51 7} less {51 8} Meta_comma {51 9} Meta_less {51 10} Meta_comma {51 11} Meta_less {51 12} Meta_comma {51 13} Meta_less {51 14} Meta_comma {51 15} Meta_less {51 16} comma {51 17} less {51 18} comma {51 19} less {51 20} comma {51 21} less {51 22} comma {51 23} less {51 24} Meta_comma {51 25} Meta_less {51 26} Meta_comma {51 27} Meta_less {51 28} Meta_comma {51 29} Meta_less {51 30} Meta_comma {51 31} Meta_less {51 32} comma {51 33} less {51 34} comma {51 35} less {51 36} comma {51 37} less {51 38} comma {51 39} less {51 40} Meta_comma {51 41} Meta_less {51 42} Meta_comma {51 43} Meta_less {51 44} Meta_comma {51 45} Meta_less {51 46} Meta_comma {51 47} Meta_less {51 48} comma {51 49} less {51 50} comma {51 51} less {51 52} comma {51 53} less {51 54} comma {51 55} less {51 56} Meta_comma {51 57} Meta_less {51 58} Meta_comma {51 59} Meta_less {51 60} Meta_comma {51 61} Meta_less {51 62} Meta_comma {51 63} Meta_less {51 64} comma {51 65} less {51 66} comma {51 67} less {51 68} comma {51 69} less {51 70} comma {51 71} less {51 72} Meta_comma {51 73} Meta_less {51 74} Meta_comma {51 75} Meta_less {51 76} Meta_comma {51 77} Meta_less {51 78} Meta_comma {51 79} Meta_less {51 80} comma {51 81} less {51 82} comma {51 83} less {51 84} comma {51 85} less {51 86} comma {51 87} less {51 88} Meta_comma {51 89} Meta_less {51 90} Meta_comma {51 91} Meta_less {51 92} Meta_comma {51 93} Meta_less {51 94} Meta_comma {51 95} Meta_less {51 96} comma {51 97} less {51 98} comma {51 99} less {51 100} comma {51 101} less {51 102} comma {51 103} less {51 104} Meta_comma {51 105} Meta_less {51 106} Meta_comma {51 107} Meta_less {51 108} Meta_comma {51 109} Meta_less {51 110} Meta_comma {51 111} Meta_less {51 112} comma {51 113} less {51 114} comma {51 115} less {51 116} comma {51 117} less {51 118} comma {51 119} less {51 120} Meta_comma {51 121} Meta_less {51 122} Meta_comma {51 123} Meta_less {51 124} Meta_comma {51 125} Meta_less {51 126} Meta_comma {51 127} Meta_less {52 0} period {52 1} greater {52 2} period {52 3} greater {52 4} Compose {52 5} Compose {52 6} Compose {52 7} Compose {52 8} Meta_period {52 9} Meta_greater {52 10} Meta_period {52 11} Meta_greater {52 12} Compose {52 13} Compose {52 14} Compose {52 15} Compose {52 16} period {52 17} greater {52 18} period {52 19} greater {52 20} Compose {52 21} Compose {52 22} Compose {52 23} Compose {52 24} Meta_period {52 25} Meta_greater {52 26} Meta_period {52 27} Meta_greater {52 28} Compose {52 29} Compose {52 30} Compose {52 31} Compose {52 32} period {52 33} greater {52 34} period {52 35} greater {52 36} Compose {52 37} Compose {52 38} Compose {52 39} Compose {52 40} Meta_period {52 41} Meta_greater {52 42} Meta_period {52 43} Meta_greater {52 44} Compose {52 45} Compose {52 46} Compose {52 47} Compose {52 48} period {52 49} greater {52 50} period {52 51} greater {52 52} Compose {52 53} Compose {52 54} Compose {52 55} Compose {52 56} Meta_period {52 57} Meta_greater {52 58} Meta_period {52 59} Meta_greater {52 60} Compose {52 61} Compose {52 62} Compose {52 63} Compose {52 64} period {52 65} greater {52 66} period {52 67} greater {52 68} Compose {52 69} Compose {52 70} Compose {52 71} Compose {52 72} Meta_period {52 73} Meta_greater {52 74} Meta_period {52 75} Meta_greater {52 76} Compose {52 77} Compose {52 78} Compose {52 79} Compose {52 80} period {52 81} greater {52 82} period {52 83} greater {52 84} Compose {52 85} Compose {52 86} Compose {52 87} Compose {52 88} Meta_period {52 89} Meta_greater {52 90} Meta_period {52 91} Meta_greater {52 92} Compose {52 93} Compose {52 94} Compose {52 95} Compose {52 96} period {52 97} greater {52 98} period {52 99} greater {52 100} Compose {52 101} Compose {52 102} Compose {52 103} Compose {52 104} Meta_period {52 105} Meta_greater {52 106} Meta_period {52 107} Meta_greater {52 108} Compose {52 109} Compose {52 110} Compose {52 111} Compose {52 112} period {52 113} greater {52 114} period {52 115} greater {52 116} Compose {52 117} Compose {52 118} Compose {52 119} Compose {52 120} Meta_period {52 121} Meta_greater {52 122} Meta_period {52 123} Meta_greater {52 124} Compose {52 125} Compose {52 126} Compose {52 127} Compose {53 0} slash {53 1} question {53 2} slash {53 3} question {53 4} Delete {53 5} Delete {53 6} Delete {53 7} Delete {53 8} Meta_slash {53 9} Meta_question {53 10} Meta_slash {53 11} Meta_question {53 12} Meta_Delete {53 13} Meta_Delete {53 14} Meta_Delete {53 15} Meta_Delete {53 16} slash {53 17} question {53 18} slash {53 19} question {53 20} Delete {53 21} Delete {53 22} Delete {53 23} Delete {53 24} Meta_slash {53 25} Meta_question {53 26} Meta_slash {53 27} Meta_question {53 28} Meta_Delete {53 29} Meta_Delete {53 30} Meta_Delete {53 31} Meta_Delete {53 32} slash {53 33} question {53 34} slash {53 35} question {53 36} Delete {53 37} Delete {53 38} Delete {53 39} Delete {53 40} Meta_slash {53 41} Meta_question {53 42} Meta_slash {53 43} Meta_question {53 44} Meta_Delete {53 45} Meta_Delete {53 46} Meta_Delete {53 47} Meta_Delete {53 48} slash {53 49} question {53 50} slash {53 51} question {53 52} Delete {53 53} Delete {53 54} Delete {53 55} Delete {53 56} Meta_slash {53 57} Meta_question {53 58} Meta_slash {53 59} Meta_question {53 60} Meta_Delete {53 61} Meta_Delete {53 62} Meta_Delete {53 63} Meta_Delete {53 64} slash {53 65} question {53 66} slash {53 67} question {53 68} Delete {53 69} Delete {53 70} Delete {53 71} Delete {53 72} Meta_slash {53 73} Meta_question {53 74} Meta_slash {53 75} Meta_question {53 76} Meta_Delete {53 77} Meta_Delete {53 78} Meta_Delete {53 79} Meta_Delete {53 80} slash {53 81} question {53 82} slash {53 83} question {53 84} Delete {53 85} Delete {53 86} Delete {53 87} Delete {53 88} Meta_slash {53 89} Meta_question {53 90} Meta_slash {53 91} Meta_question {53 92} Meta_Delete {53 93} Meta_Delete {53 94} Meta_Delete {53 95} Meta_Delete {53 96} slash {53 97} question {53 98} slash {53 99} question {53 100} Delete {53 101} Delete {53 102} Delete {53 103} Delete {53 104} Meta_slash {53 105} Meta_question {53 106} Meta_slash {53 107} Meta_question {53 108} Meta_Delete {53 109} Meta_Delete {53 110} Meta_Delete {53 111} Meta_Delete {53 112} slash {53 113} question {53 114} slash {53 115} question {53 116} Delete {53 117} Delete {53 118} Delete {53 119} Delete {53 120} Meta_slash {53 121} Meta_question {53 122} Meta_slash {53 123} Meta_question {53 124} Meta_Delete {53 125} Meta_Delete {53 126} Meta_Delete {53 127} Meta_Delete {54 0} Shift {54 1} Shift {54 2} Shift {54 3} Shift {54 4} Shift {54 5} Shift {54 6} Shift {54 7} Shift {54 8} Shift {54 9} Shift {54 10} Shift {54 11} Shift {54 12} Shift {54 13} Shift {54 14} Shift {54 15} Shift {54 16} Shift {54 17} Shift {54 18} Shift {54 19} Shift {54 20} Shift {54 21} Shift {54 22} Shift {54 23} Shift {54 24} Shift {54 25} Shift {54 26} Shift {54 27} Shift {54 28} Shift {54 29} Shift {54 30} Shift {54 31} Shift {54 32} Shift {54 33} Shift {54 34} Shift {54 35} Shift {54 36} Shift {54 37} Shift {54 38} Shift {54 39} Shift {54 40} Shift {54 41} Shift {54 42} Shift {54 43} Shift {54 44} Shift {54 45} Shift {54 46} Shift {54 47} Shift {54 48} Shift {54 49} Shift {54 50} Shift {54 51} Shift {54 52} Shift {54 53} Shift {54 54} Shift {54 55} Shift {54 56} Shift {54 57} Shift {54 58} Shift {54 59} Shift {54 60} Shift {54 61} Shift {54 62} Shift {54 63} Shift {54 64} Shift {54 65} Shift {54 66} Shift {54 67} Shift {54 68} Shift {54 69} Shift {54 70} Shift {54 71} Shift {54 72} Shift {54 73} Shift {54 74} Shift {54 75} Shift {54 76} Shift {54 77} Shift {54 78} Shift {54 79} Shift {54 80} Shift {54 81} Shift {54 82} Shift {54 83} Shift {54 84} Shift {54 85} Shift {54 86} Shift {54 87} Shift {54 88} Shift {54 89} Shift {54 90} Shift {54 91} Shift {54 92} Shift {54 93} Shift {54 94} Shift {54 95} Shift {54 96} Shift {54 97} Shift {54 98} Shift {54 99} Shift {54 100} Shift {54 101} Shift {54 102} Shift {54 103} Shift {54 104} Shift {54 105} Shift {54 106} Shift {54 107} Shift {54 108} Shift {54 109} Shift {54 110} Shift {54 111} Shift {54 112} Shift {54 113} Shift {54 114} Shift {54 115} Shift {54 116} Shift {54 117} Shift {54 118} Shift {54 119} Shift {54 120} Shift {54 121} Shift {54 122} Shift {54 123} Shift {54 124} Shift {54 125} Shift {54 126} Shift {54 127} Shift {55 0} KP_Multiply {55 1} KP_Multiply {55 2} Hex_C {55 3} KP_Multiply {55 4} KP_Multiply {55 5} KP_Multiply {55 6} KP_Multiply {55 7} KP_Multiply {55 8} KP_Multiply {55 9} Hex_C {55 10} KP_Multiply {55 11} KP_Multiply {55 12} KP_Multiply {55 13} KP_Multiply {55 14} KP_Multiply {55 15} KP_Multiply {55 16} KP_Multiply {55 17} KP_Multiply {55 18} Hex_C {55 19} KP_Multiply {55 20} KP_Multiply {55 21} KP_Multiply {55 22} KP_Multiply {55 23} KP_Multiply {55 24} KP_Multiply {55 25} Hex_C {55 26} KP_Multiply {55 27} KP_Multiply {55 28} KP_Multiply {55 29} KP_Multiply {55 30} KP_Multiply {55 31} KP_Multiply {55 32} KP_Multiply {55 33} KP_Multiply {55 34} Hex_C {55 35} KP_Multiply {55 36} KP_Multiply {55 37} KP_Multiply {55 38} KP_Multiply {55 39} KP_Multiply {55 40} KP_Multiply {55 41} Hex_C {55 42} KP_Multiply {55 43} KP_Multiply {55 44} KP_Multiply {55 45} KP_Multiply {55 46} KP_Multiply {55 47} KP_Multiply {55 48} KP_Multiply {55 49} KP_Multiply {55 50} Hex_C {55 51} KP_Multiply {55 52} KP_Multiply {55 53} KP_Multiply {55 54} KP_Multiply {55 55} KP_Multiply {55 56} KP_Multiply {55 57} Hex_C {55 58} KP_Multiply {55 59} KP_Multiply {55 60} KP_Multiply {55 61} KP_Multiply {55 62} KP_Multiply {55 63} KP_Multiply {55 64} KP_Multiply {55 65} KP_Multiply {55 66} Hex_C {55 67} KP_Multiply {55 68} KP_Multiply {55 69} KP_Multiply {55 70} KP_Multiply {55 71} KP_Multiply {55 72} KP_Multiply {55 73} Hex_C {55 74} KP_Multiply {55 75} KP_Multiply {55 76} KP_Multiply {55 77} KP_Multiply {55 78} KP_Multiply {55 79} KP_Multiply {55 80} KP_Multiply {55 81} KP_Multiply {55 82} Hex_C {55 83} KP_Multiply {55 84} KP_Multiply {55 85} KP_Multiply {55 86} KP_Multiply {55 87} KP_Multiply {55 88} KP_Multiply {55 89} Hex_C {55 90} KP_Multiply {55 91} KP_Multiply {55 92} KP_Multiply {55 93} KP_Multiply {55 94} KP_Multiply {55 95} KP_Multiply {55 96} KP_Multiply {55 97} KP_Multiply {55 98} Hex_C {55 99} KP_Multiply {55 100} KP_Multiply {55 101} KP_Multiply {55 102} KP_Multiply {55 103} KP_Multiply {55 104} KP_Multiply {55 105} Hex_C {55 106} KP_Multiply {55 107} KP_Multiply {55 108} KP_Multiply {55 109} KP_Multiply {55 110} KP_Multiply {55 111} KP_Multiply {55 112} KP_Multiply {55 113} KP_Multiply {55 114} Hex_C {55 115} KP_Multiply {55 116} KP_Multiply {55 117} KP_Multiply {55 118} KP_Multiply {55 119} KP_Multiply {55 120} KP_Multiply {55 121} Hex_C {55 122} KP_Multiply {55 123} KP_Multiply {55 124} KP_Multiply {55 125} KP_Multiply {55 126} KP_Multiply {55 127} KP_Multiply {56 0} Alt {56 1} Alt {56 2} Alt {56 3} Alt {56 4} Alt {56 5} Alt {56 6} Alt {56 7} Alt {56 8} Alt {56 9} Alt {56 10} Alt {56 11} Alt {56 12} Alt {56 13} Alt {56 14} Alt {56 15} Alt {56 16} Alt {56 17} Alt {56 18} Alt {56 19} Alt {56 20} Alt {56 21} Alt {56 22} Alt {56 23} Alt {56 24} Alt {56 25} Alt {56 26} Alt {56 27} Alt {56 28} Alt {56 29} Alt {56 30} Alt {56 31} Alt {56 32} Alt {56 33} Alt {56 34} Alt {56 35} Alt {56 36} Alt {56 37} Alt {56 38} Alt {56 39} Alt {56 40} Alt {56 41} Alt {56 42} Alt {56 43} Alt {56 44} Alt {56 45} Alt {56 46} Alt {56 47} Alt {56 48} Alt {56 49} Alt {56 50} Alt {56 51} Alt {56 52} Alt {56 53} Alt {56 54} Alt {56 55} Alt {56 56} Alt {56 57} Alt {56 58} Alt {56 59} Alt {56 60} Alt {56 61} Alt {56 62} Alt {56 63} Alt {56 64} Alt {56 65} Alt {56 66} Alt {56 67} Alt {56 68} Alt {56 69} Alt {56 70} Alt {56 71} Alt {56 72} Alt {56 73} Alt {56 74} Alt {56 75} Alt {56 76} Alt {56 77} Alt {56 78} Alt {56 79} Alt {56 80} Alt {56 81} Alt {56 82} Alt {56 83} Alt {56 84} Alt {56 85} Alt {56 86} Alt {56 87} Alt {56 88} Alt {56 89} Alt {56 90} Alt {56 91} Alt {56 92} Alt {56 93} Alt {56 94} Alt {56 95} Alt {56 96} Alt {56 97} Alt {56 98} Alt {56 99} Alt {56 100} Alt {56 101} Alt {56 102} Alt {56 103} Alt {56 104} Alt {56 105} Alt {56 106} Alt {56 107} Alt {56 108} Alt {56 109} Alt {56 110} Alt {56 111} Alt {56 112} Alt {56 113} Alt {56 114} Alt {56 115} Alt {56 116} Alt {56 117} Alt {56 118} Alt {56 119} Alt {56 120} Alt {56 121} Alt {56 122} Alt {56 123} Alt {56 124} Alt {56 125} Alt {56 126} Alt {56 127} Alt {57 0} space {57 1} space {57 2} space {57 3} space {57 4} nul {57 5} nul {57 6} nul {57 7} nul {57 8} Meta_space {57 9} Meta_space {57 10} Meta_space {57 11} Meta_space {57 12} Meta_nul {57 13} Meta_nul {57 14} Meta_nul {57 15} Meta_nul {57 16} space {57 17} space {57 18} space {57 19} space {57 20} nul {57 21} nul {57 22} nul {57 23} nul {57 24} Meta_space {57 25} Meta_space {57 26} Meta_space {57 27} Meta_space {57 28} Meta_nul {57 29} Meta_nul {57 30} Meta_nul {57 31} Meta_nul {57 32} space {57 33} space {57 34} space {57 35} space {57 36} nul {57 37} nul {57 38} nul {57 39} nul {57 40} Meta_space {57 41} Meta_space {57 42} Meta_space {57 43} Meta_space {57 44} Meta_nul {57 45} Meta_nul {57 46} Meta_nul {57 47} Meta_nul {57 48} space {57 49} space {57 50} space {57 51} space {57 52} nul {57 53} nul {57 54} nul {57 55} nul {57 56} Meta_space {57 57} Meta_space {57 58} Meta_space {57 59} Meta_space {57 60} Meta_nul {57 61} Meta_nul {57 62} Meta_nul {57 63} Meta_nul {57 64} space {57 65} space {57 66} space {57 67} space {57 68} nul {57 69} nul {57 70} nul {57 71} nul {57 72} Meta_space {57 73} Meta_space {57 74} Meta_space {57 75} Meta_space {57 76} Meta_nul {57 77} Meta_nul {57 78} Meta_nul {57 79} Meta_nul {57 80} space {57 81} space {57 82} space {57 83} space {57 84} nul {57 85} nul {57 86} nul {57 87} nul {57 88} Meta_space {57 89} Meta_space {57 90} Meta_space {57 91} Meta_space {57 92} Meta_nul {57 93} Meta_nul {57 94} Meta_nul {57 95} Meta_nul {57 96} space {57 97} space {57 98} space {57 99} space {57 100} nul {57 101} nul {57 102} nul {57 103} nul {57 104} Meta_space {57 105} Meta_space {57 106} Meta_space {57 107} Meta_space {57 108} Meta_nul {57 109} Meta_nul {57 110} Meta_nul {57 111} Meta_nul {57 112} space {57 113} space {57 114} space {57 115} space {57 116} nul {57 117} nul {57 118} nul {57 119} nul {57 120} Meta_space {57 121} Meta_space {57 122} Meta_space {57 123} Meta_space {57 124} Meta_nul {57 125} Meta_nul {57 126} Meta_nul {57 127} Meta_nul {58 0} Caps_Lock {58 1} Caps_Lock {58 2} Caps_Lock {58 3} Caps_Lock {58 4} Caps_Lock {58 5} Caps_Lock {58 6} Caps_Lock {58 7} Caps_Lock {58 8} Caps_Lock {58 9} Caps_Lock {58 10} Caps_Lock {58 11} Caps_Lock {58 12} Caps_Lock {58 13} Caps_Lock {58 14} Caps_Lock {58 15} Caps_Lock {58 16} Caps_Lock {58 17} Caps_Lock {58 18} Caps_Lock {58 19} Caps_Lock {58 20} Caps_Lock {58 21} Caps_Lock {58 22} Caps_Lock {58 23} Caps_Lock {58 24} Caps_Lock {58 25} Caps_Lock {58 26} Caps_Lock {58 27} Caps_Lock {58 28} Caps_Lock {58 29} Caps_Lock {58 30} Caps_Lock {58 31} Caps_Lock {58 32} Caps_Lock {58 33} Caps_Lock {58 34} Caps_Lock {58 35} Caps_Lock {58 36} Caps_Lock {58 37} Caps_Lock {58 38} Caps_Lock {58 39} Caps_Lock {58 40} Caps_Lock {58 41} Caps_Lock {58 42} Caps_Lock {58 43} Caps_Lock {58 44} Caps_Lock {58 45} Caps_Lock {58 46} Caps_Lock {58 47} Caps_Lock {58 48} Caps_Lock {58 49} Caps_Lock {58 50} Caps_Lock {58 51} Caps_Lock {58 52} Caps_Lock {58 53} Caps_Lock {58 54} Caps_Lock {58 55} Caps_Lock {58 56} Caps_Lock {58 57} Caps_Lock {58 58} Caps_Lock {58 59} Caps_Lock {58 60} Caps_Lock {58 61} Caps_Lock {58 62} Caps_Lock {58 63} Caps_Lock {58 64} Caps_Lock {58 65} Caps_Lock {58 66} Caps_Lock {58 67} Caps_Lock {58 68} Caps_Lock {58 69} Caps_Lock {58 70} Caps_Lock {58 71} Caps_Lock {58 72} Caps_Lock {58 73} Caps_Lock {58 74} Caps_Lock {58 75} Caps_Lock {58 76} Caps_Lock {58 77} Caps_Lock {58 78} Caps_Lock {58 79} Caps_Lock {58 80} Caps_Lock {58 81} Caps_Lock {58 82} Caps_Lock {58 83} Caps_Lock {58 84} Caps_Lock {58 85} Caps_Lock {58 86} Caps_Lock {58 87} Caps_Lock {58 88} Caps_Lock {58 89} Caps_Lock {58 90} Caps_Lock {58 91} Caps_Lock {58 92} Caps_Lock {58 93} Caps_Lock {58 94} Caps_Lock {58 95} Caps_Lock {58 96} Caps_Lock {58 97} Caps_Lock {58 98} Caps_Lock {58 99} Caps_Lock {58 100} Caps_Lock {58 101} Caps_Lock {58 102} Caps_Lock {58 103} Caps_Lock {58 104} Caps_Lock {58 105} Caps_Lock {58 106} Caps_Lock {58 107} Caps_Lock {58 108} Caps_Lock {58 109} Caps_Lock {58 110} Caps_Lock {58 111} Caps_Lock {58 112} Caps_Lock {58 113} Caps_Lock {58 114} Caps_Lock {58 115} Caps_Lock {58 116} Caps_Lock {58 117} Caps_Lock {58 118} Caps_Lock {58 119} Caps_Lock {58 120} Caps_Lock {58 121} Caps_Lock {58 122} Caps_Lock {58 123} Caps_Lock {58 124} Caps_Lock {58 125} Caps_Lock {58 126} Caps_Lock {58 127} Caps_Lock {59 0} F1 {59 1} F13 {59 2} Console_13 {59 3} Console_25 {59 4} F25 {59 5} F37 {59 6} Console_13 {59 7} Console_25 {59 8} Console_1 {59 9} Console_13 {59 10} F1 {59 11} F1 {59 12} Console_1 {59 13} Console_13 {59 14} F1 {59 15} F1 {59 16} F1 {59 17} F13 {59 18} Console_13 {59 19} Console_25 {59 20} F25 {59 21} F37 {59 22} Console_13 {59 23} Console_25 {59 24} Console_1 {59 25} Console_13 {59 26} F1 {59 27} F1 {59 28} Console_1 {59 29} Console_13 {59 30} F1 {59 31} F1 {59 32} F1 {59 33} F13 {59 34} Console_13 {59 35} Console_25 {59 36} F25 {59 37} F37 {59 38} Console_13 {59 39} Console_25 {59 40} Console_1 {59 41} Console_13 {59 42} F1 {59 43} F1 {59 44} Console_1 {59 45} Console_13 {59 46} F1 {59 47} F1 {59 48} F1 {59 49} F13 {59 50} Console_13 {59 51} Console_25 {59 52} F25 {59 53} F37 {59 54} Console_13 {59 55} Console_25 {59 56} Console_1 {59 57} Console_13 {59 58} F1 {59 59} F1 {59 60} Console_1 {59 61} Console_13 {59 62} F1 {59 63} F1 {59 64} F1 {59 65} F13 {59 66} Console_13 {59 67} Console_25 {59 68} F25 {59 69} F37 {59 70} Console_13 {59 71} Console_25 {59 72} Console_1 {59 73} Console_13 {59 74} F1 {59 75} F1 {59 76} Console_1 {59 77} Console_13 {59 78} F1 {59 79} F1 {59 80} F1 {59 81} F13 {59 82} Console_13 {59 83} Console_25 {59 84} F25 {59 85} F37 {59 86} Console_13 {59 87} Console_25 {59 88} Console_1 {59 89} Console_13 {59 90} F1 {59 91} F1 {59 92} Console_1 {59 93} Console_13 {59 94} F1 {59 95} F1 {59 96} F1 {59 97} F13 {59 98} Console_13 {59 99} Console_25 {59 100} F25 {59 101} F37 {59 102} Console_13 {59 103} Console_25 {59 104} Console_1 {59 105} Console_13 {59 106} F1 {59 107} F1 {59 108} Console_1 {59 109} Console_13 {59 110} F1 {59 111} F1 {59 112} F1 {59 113} F13 {59 114} Console_13 {59 115} Console_25 {59 116} F25 {59 117} F37 {59 118} Console_13 {59 119} Console_25 {59 120} Console_1 {59 121} Console_13 {59 122} F1 {59 123} F1 {59 124} Console_1 {59 125} Console_13 {59 126} F1 {59 127} F1 {60 0} F2 {60 1} F14 {60 2} Console_14 {60 3} Console_26 {60 4} F26 {60 5} F38 {60 6} Console_14 {60 7} Console_26 {60 8} Console_2 {60 9} Console_14 {60 10} F2 {60 11} F2 {60 12} Console_2 {60 13} Console_14 {60 14} F2 {60 15} F2 {60 16} F2 {60 17} F14 {60 18} Console_14 {60 19} Console_26 {60 20} F26 {60 21} F38 {60 22} Console_14 {60 23} Console_26 {60 24} Console_2 {60 25} Console_14 {60 26} F2 {60 27} F2 {60 28} Console_2 {60 29} Console_14 {60 30} F2 {60 31} F2 {60 32} F2 {60 33} F14 {60 34} Console_14 {60 35} Console_26 {60 36} F26 {60 37} F38 {60 38} Console_14 {60 39} Console_26 {60 40} Console_2 {60 41} Console_14 {60 42} F2 {60 43} F2 {60 44} Console_2 {60 45} Console_14 {60 46} F2 {60 47} F2 {60 48} F2 {60 49} F14 {60 50} Console_14 {60 51} Console_26 {60 52} F26 {60 53} F38 {60 54} Console_14 {60 55} Console_26 {60 56} Console_2 {60 57} Console_14 {60 58} F2 {60 59} F2 {60 60} Console_2 {60 61} Console_14 {60 62} F2 {60 63} F2 {60 64} F2 {60 65} F14 {60 66} Console_14 {60 67} Console_26 {60 68} F26 {60 69} F38 {60 70} Console_14 {60 71} Console_26 {60 72} Console_2 {60 73} Console_14 {60 74} F2 {60 75} F2 {60 76} Console_2 {60 77} Console_14 {60 78} F2 {60 79} F2 {60 80} F2 {60 81} F14 {60 82} Console_14 {60 83} Console_26 {60 84} F26 {60 85} F38 {60 86} Console_14 {60 87} Console_26 {60 88} Console_2 {60 89} Console_14 {60 90} F2 {60 91} F2 {60 92} Console_2 {60 93} Console_14 {60 94} F2 {60 95} F2 {60 96} F2 {60 97} F14 {60 98} Console_14 {60 99} Console_26 {60 100} F26 {60 101} F38 {60 102} Console_14 {60 103} Console_26 {60 104} Console_2 {60 105} Console_14 {60 106} F2 {60 107} F2 {60 108} Console_2 {60 109} Console_14 {60 110} F2 {60 111} F2 {60 112} F2 {60 113} F14 {60 114} Console_14 {60 115} Console_26 {60 116} F26 {60 117} F38 {60 118} Console_14 {60 119} Console_26 {60 120} Console_2 {60 121} Console_14 {60 122} F2 {60 123} F2 {60 124} Console_2 {60 125} Console_14 {60 126} F2 {60 127} F2 {61 0} F3 {61 1} F15 {61 2} Console_15 {61 3} Console_27 {61 4} F27 {61 5} F39 {61 6} Console_15 {61 7} Console_27 {61 8} Console_3 {61 9} Console_15 {61 10} F3 {61 11} F3 {61 12} Console_3 {61 13} Console_15 {61 14} F3 {61 15} F3 {61 16} F3 {61 17} F15 {61 18} Console_15 {61 19} Console_27 {61 20} F27 {61 21} F39 {61 22} Console_15 {61 23} Console_27 {61 24} Console_3 {61 25} Console_15 {61 26} F3 {61 27} F3 {61 28} Console_3 {61 29} Console_15 {61 30} F3 {61 31} F3 {61 32} F3 {61 33} F15 {61 34} Console_15 {61 35} Console_27 {61 36} F27 {61 37} F39 {61 38} Console_15 {61 39} Console_27 {61 40} Console_3 {61 41} Console_15 {61 42} F3 {61 43} F3 {61 44} Console_3 {61 45} Console_15 {61 46} F3 {61 47} F3 {61 48} F3 {61 49} F15 {61 50} Console_15 {61 51} Console_27 {61 52} F27 {61 53} F39 {61 54} Console_15 {61 55} Console_27 {61 56} Console_3 {61 57} Console_15 {61 58} F3 {61 59} F3 {61 60} Console_3 {61 61} Console_15 {61 62} F3 {61 63} F3 {61 64} F3 {61 65} F15 {61 66} Console_15 {61 67} Console_27 {61 68} F27 {61 69} F39 {61 70} Console_15 {61 71} Console_27 {61 72} Console_3 {61 73} Console_15 {61 74} F3 {61 75} F3 {61 76} Console_3 {61 77} Console_15 {61 78} F3 {61 79} F3 {61 80} F3 {61 81} F15 {61 82} Console_15 {61 83} Console_27 {61 84} F27 {61 85} F39 {61 86} Console_15 {61 87} Console_27 {61 88} Console_3 {61 89} Console_15 {61 90} F3 {61 91} F3 {61 92} Console_3 {61 93} Console_15 {61 94} F3 {61 95} F3 {61 96} F3 {61 97} F15 {61 98} Console_15 {61 99} Console_27 {61 100} F27 {61 101} F39 {61 102} Console_15 {61 103} Console_27 {61 104} Console_3 {61 105} Console_15 {61 106} F3 {61 107} F3 {61 108} Console_3 {61 109} Console_15 {61 110} F3 {61 111} F3 {61 112} F3 {61 113} F15 {61 114} Console_15 {61 115} Console_27 {61 116} F27 {61 117} F39 {61 118} Console_15 {61 119} Console_27 {61 120} Console_3 {61 121} Console_15 {61 122} F3 {61 123} F3 {61 124} Console_3 {61 125} Console_15 {61 126} F3 {61 127} F3 {62 0} F4 {62 1} F16 {62 2} Console_16 {62 3} Console_28 {62 4} F28 {62 5} F40 {62 6} Console_16 {62 7} Console_28 {62 8} Console_4 {62 9} Console_16 {62 10} F4 {62 11} F4 {62 12} Console_4 {62 13} Console_16 {62 14} F4 {62 15} F4 {62 16} F4 {62 17} F16 {62 18} Console_16 {62 19} Console_28 {62 20} F28 {62 21} F40 {62 22} Console_16 {62 23} Console_28 {62 24} Console_4 {62 25} Console_16 {62 26} F4 {62 27} F4 {62 28} Console_4 {62 29} Console_16 {62 30} F4 {62 31} F4 {62 32} F4 {62 33} F16 {62 34} Console_16 {62 35} Console_28 {62 36} F28 {62 37} F40 {62 38} Console_16 {62 39} Console_28 {62 40} Console_4 {62 41} Console_16 {62 42} F4 {62 43} F4 {62 44} Console_4 {62 45} Console_16 {62 46} F4 {62 47} F4 {62 48} F4 {62 49} F16 {62 50} Console_16 {62 51} Console_28 {62 52} F28 {62 53} F40 {62 54} Console_16 {62 55} Console_28 {62 56} Console_4 {62 57} Console_16 {62 58} F4 {62 59} F4 {62 60} Console_4 {62 61} Console_16 {62 62} F4 {62 63} F4 {62 64} F4 {62 65} F16 {62 66} Console_16 {62 67} Console_28 {62 68} F28 {62 69} F40 {62 70} Console_16 {62 71} Console_28 {62 72} Console_4 {62 73} Console_16 {62 74} F4 {62 75} F4 {62 76} Console_4 {62 77} Console_16 {62 78} F4 {62 79} F4 {62 80} F4 {62 81} F16 {62 82} Console_16 {62 83} Console_28 {62 84} F28 {62 85} F40 {62 86} Console_16 {62 87} Console_28 {62 88} Console_4 {62 89} Console_16 {62 90} F4 {62 91} F4 {62 92} Console_4 {62 93} Console_16 {62 94} F4 {62 95} F4 {62 96} F4 {62 97} F16 {62 98} Console_16 {62 99} Console_28 {62 100} F28 {62 101} F40 {62 102} Console_16 {62 103} Console_28 {62 104} Console_4 {62 105} Console_16 {62 106} F4 {62 107} F4 {62 108} Console_4 {62 109} Console_16 {62 110} F4 {62 111} F4 {62 112} F4 {62 113} F16 {62 114} Console_16 {62 115} Console_28 {62 116} F28 {62 117} F40 {62 118} Console_16 {62 119} Console_28 {62 120} Console_4 {62 121} Console_16 {62 122} F4 {62 123} F4 {62 124} Console_4 {62 125} Console_16 {62 126} F4 {62 127} F4 {63 0} F5 {63 1} F17 {63 2} Console_17 {63 3} Console_29 {63 4} F29 {63 5} F41 {63 6} Console_17 {63 7} Console_29 {63 8} Console_5 {63 9} Console_17 {63 10} F5 {63 11} F5 {63 12} Console_5 {63 13} Console_17 {63 14} F5 {63 15} F5 {63 16} F5 {63 17} F17 {63 18} Console_17 {63 19} Console_29 {63 20} F29 {63 21} F41 {63 22} Console_17 {63 23} Console_29 {63 24} Console_5 {63 25} Console_17 {63 26} F5 {63 27} F5 {63 28} Console_5 {63 29} Console_17 {63 30} F5 {63 31} F5 {63 32} F5 {63 33} F17 {63 34} Console_17 {63 35} Console_29 {63 36} F29 {63 37} F41 {63 38} Console_17 {63 39} Console_29 {63 40} Console_5 {63 41} Console_17 {63 42} F5 {63 43} F5 {63 44} Console_5 {63 45} Console_17 {63 46} F5 {63 47} F5 {63 48} F5 {63 49} F17 {63 50} Console_17 {63 51} Console_29 {63 52} F29 {63 53} F41 {63 54} Console_17 {63 55} Console_29 {63 56} Console_5 {63 57} Console_17 {63 58} F5 {63 59} F5 {63 60} Console_5 {63 61} Console_17 {63 62} F5 {63 63} F5 {63 64} F5 {63 65} F17 {63 66} Console_17 {63 67} Console_29 {63 68} F29 {63 69} F41 {63 70} Console_17 {63 71} Console_29 {63 72} Console_5 {63 73} Console_17 {63 74} F5 {63 75} F5 {63 76} Console_5 {63 77} Console_17 {63 78} F5 {63 79} F5 {63 80} F5 {63 81} F17 {63 82} Console_17 {63 83} Console_29 {63 84} F29 {63 85} F41 {63 86} Console_17 {63 87} Console_29 {63 88} Console_5 {63 89} Console_17 {63 90} F5 {63 91} F5 {63 92} Console_5 {63 93} Console_17 {63 94} F5 {63 95} F5 {63 96} F5 {63 97} F17 {63 98} Console_17 {63 99} Console_29 {63 100} F29 {63 101} F41 {63 102} Console_17 {63 103} Console_29 {63 104} Console_5 {63 105} Console_17 {63 106} F5 {63 107} F5 {63 108} Console_5 {63 109} Console_17 {63 110} F5 {63 111} F5 {63 112} F5 {63 113} F17 {63 114} Console_17 {63 115} Console_29 {63 116} F29 {63 117} F41 {63 118} Console_17 {63 119} Console_29 {63 120} Console_5 {63 121} Console_17 {63 122} F5 {63 123} F5 {63 124} Console_5 {63 125} Console_17 {63 126} F5 {63 127} F5 {64 0} F6 {64 1} F18 {64 2} Console_18 {64 3} Console_30 {64 4} F30 {64 5} F42 {64 6} Console_18 {64 7} Console_30 {64 8} Console_6 {64 9} Console_18 {64 10} F6 {64 11} F6 {64 12} Console_6 {64 13} Console_18 {64 14} F6 {64 15} F6 {64 16} F6 {64 17} F18 {64 18} Console_18 {64 19} Console_30 {64 20} F30 {64 21} F42 {64 22} Console_18 {64 23} Console_30 {64 24} Console_6 {64 25} Console_18 {64 26} F6 {64 27} F6 {64 28} Console_6 {64 29} Console_18 {64 30} F6 {64 31} F6 {64 32} F6 {64 33} F18 {64 34} Console_18 {64 35} Console_30 {64 36} F30 {64 37} F42 {64 38} Console_18 {64 39} Console_30 {64 40} Console_6 {64 41} Console_18 {64 42} F6 {64 43} F6 {64 44} Console_6 {64 45} Console_18 {64 46} F6 {64 47} F6 {64 48} F6 {64 49} F18 {64 50} Console_18 {64 51} Console_30 {64 52} F30 {64 53} F42 {64 54} Console_18 {64 55} Console_30 {64 56} Console_6 {64 57} Console_18 {64 58} F6 {64 59} F6 {64 60} Console_6 {64 61} Console_18 {64 62} F6 {64 63} F6 {64 64} F6 {64 65} F18 {64 66} Console_18 {64 67} Console_30 {64 68} F30 {64 69} F42 {64 70} Console_18 {64 71} Console_30 {64 72} Console_6 {64 73} Console_18 {64 74} F6 {64 75} F6 {64 76} Console_6 {64 77} Console_18 {64 78} F6 {64 79} F6 {64 80} F6 {64 81} F18 {64 82} Console_18 {64 83} Console_30 {64 84} F30 {64 85} F42 {64 86} Console_18 {64 87} Console_30 {64 88} Console_6 {64 89} Console_18 {64 90} F6 {64 91} F6 {64 92} Console_6 {64 93} Console_18 {64 94} F6 {64 95} F6 {64 96} F6 {64 97} F18 {64 98} Console_18 {64 99} Console_30 {64 100} F30 {64 101} F42 {64 102} Console_18 {64 103} Console_30 {64 104} Console_6 {64 105} Console_18 {64 106} F6 {64 107} F6 {64 108} Console_6 {64 109} Console_18 {64 110} F6 {64 111} F6 {64 112} F6 {64 113} F18 {64 114} Console_18 {64 115} Console_30 {64 116} F30 {64 117} F42 {64 118} Console_18 {64 119} Console_30 {64 120} Console_6 {64 121} Console_18 {64 122} F6 {64 123} F6 {64 124} Console_6 {64 125} Console_18 {64 126} F6 {64 127} F6 {65 0} F7 {65 1} F19 {65 2} Console_19 {65 3} Console_31 {65 4} F31 {65 5} F43 {65 6} Console_19 {65 7} Console_31 {65 8} Console_7 {65 9} Console_19 {65 10} F7 {65 11} F7 {65 12} Console_7 {65 13} Console_19 {65 14} F7 {65 15} F7 {65 16} F7 {65 17} F19 {65 18} Console_19 {65 19} Console_31 {65 20} F31 {65 21} F43 {65 22} Console_19 {65 23} Console_31 {65 24} Console_7 {65 25} Console_19 {65 26} F7 {65 27} F7 {65 28} Console_7 {65 29} Console_19 {65 30} F7 {65 31} F7 {65 32} F7 {65 33} F19 {65 34} Console_19 {65 35} Console_31 {65 36} F31 {65 37} F43 {65 38} Console_19 {65 39} Console_31 {65 40} Console_7 {65 41} Console_19 {65 42} F7 {65 43} F7 {65 44} Console_7 {65 45} Console_19 {65 46} F7 {65 47} F7 {65 48} F7 {65 49} F19 {65 50} Console_19 {65 51} Console_31 {65 52} F31 {65 53} F43 {65 54} Console_19 {65 55} Console_31 {65 56} Console_7 {65 57} Console_19 {65 58} F7 {65 59} F7 {65 60} Console_7 {65 61} Console_19 {65 62} F7 {65 63} F7 {65 64} F7 {65 65} F19 {65 66} Console_19 {65 67} Console_31 {65 68} F31 {65 69} F43 {65 70} Console_19 {65 71} Console_31 {65 72} Console_7 {65 73} Console_19 {65 74} F7 {65 75} F7 {65 76} Console_7 {65 77} Console_19 {65 78} F7 {65 79} F7 {65 80} F7 {65 81} F19 {65 82} Console_19 {65 83} Console_31 {65 84} F31 {65 85} F43 {65 86} Console_19 {65 87} Console_31 {65 88} Console_7 {65 89} Console_19 {65 90} F7 {65 91} F7 {65 92} Console_7 {65 93} Console_19 {65 94} F7 {65 95} F7 {65 96} F7 {65 97} F19 {65 98} Console_19 {65 99} Console_31 {65 100} F31 {65 101} F43 {65 102} Console_19 {65 103} Console_31 {65 104} Console_7 {65 105} Console_19 {65 106} F7 {65 107} F7 {65 108} Console_7 {65 109} Console_19 {65 110} F7 {65 111} F7 {65 112} F7 {65 113} F19 {65 114} Console_19 {65 115} Console_31 {65 116} F31 {65 117} F43 {65 118} Console_19 {65 119} Console_31 {65 120} Console_7 {65 121} Console_19 {65 122} F7 {65 123} F7 {65 124} Console_7 {65 125} Console_19 {65 126} F7 {65 127} F7 {66 0} F8 {66 1} F20 {66 2} Console_20 {66 3} Console_32 {66 4} F32 {66 5} F44 {66 6} Console_20 {66 7} Console_32 {66 8} Console_8 {66 9} Console_20 {66 10} F8 {66 11} F8 {66 12} Console_8 {66 13} Console_20 {66 14} F8 {66 15} F8 {66 16} F8 {66 17} F20 {66 18} Console_20 {66 19} Console_32 {66 20} F32 {66 21} F44 {66 22} Console_20 {66 23} Console_32 {66 24} Console_8 {66 25} Console_20 {66 26} F8 {66 27} F8 {66 28} Console_8 {66 29} Console_20 {66 30} F8 {66 31} F8 {66 32} F8 {66 33} F20 {66 34} Console_20 {66 35} Console_32 {66 36} F32 {66 37} F44 {66 38} Console_20 {66 39} Console_32 {66 40} Console_8 {66 41} Console_20 {66 42} F8 {66 43} F8 {66 44} Console_8 {66 45} Console_20 {66 46} F8 {66 47} F8 {66 48} F8 {66 49} F20 {66 50} Console_20 {66 51} Console_32 {66 52} F32 {66 53} F44 {66 54} Console_20 {66 55} Console_32 {66 56} Console_8 {66 57} Console_20 {66 58} F8 {66 59} F8 {66 60} Console_8 {66 61} Console_20 {66 62} F8 {66 63} F8 {66 64} F8 {66 65} F20 {66 66} Console_20 {66 67} Console_32 {66 68} F32 {66 69} F44 {66 70} Console_20 {66 71} Console_32 {66 72} Console_8 {66 73} Console_20 {66 74} F8 {66 75} F8 {66 76} Console_8 {66 77} Console_20 {66 78} F8 {66 79} F8 {66 80} F8 {66 81} F20 {66 82} Console_20 {66 83} Console_32 {66 84} F32 {66 85} F44 {66 86} Console_20 {66 87} Console_32 {66 88} Console_8 {66 89} Console_20 {66 90} F8 {66 91} F8 {66 92} Console_8 {66 93} Console_20 {66 94} F8 {66 95} F8 {66 96} F8 {66 97} F20 {66 98} Console_20 {66 99} Console_32 {66 100} F32 {66 101} F44 {66 102} Console_20 {66 103} Console_32 {66 104} Console_8 {66 105} Console_20 {66 106} F8 {66 107} F8 {66 108} Console_8 {66 109} Console_20 {66 110} F8 {66 111} F8 {66 112} F8 {66 113} F20 {66 114} Console_20 {66 115} Console_32 {66 116} F32 {66 117} F44 {66 118} Console_20 {66 119} Console_32 {66 120} Console_8 {66 121} Console_20 {66 122} F8 {66 123} F8 {66 124} Console_8 {66 125} Console_20 {66 126} F8 {66 127} F8 {67 0} F9 {67 1} F21 {67 2} Console_21 {67 3} Console_33 {67 4} F33 {67 5} F45 {67 6} Console_21 {67 7} Console_33 {67 8} Console_9 {67 9} Console_21 {67 10} F9 {67 11} F9 {67 12} Console_9 {67 13} Console_21 {67 14} F9 {67 15} F9 {67 16} F9 {67 17} F21 {67 18} Console_21 {67 19} Console_33 {67 20} F33 {67 21} F45 {67 22} Console_21 {67 23} Console_33 {67 24} Console_9 {67 25} Console_21 {67 26} F9 {67 27} F9 {67 28} Console_9 {67 29} Console_21 {67 30} F9 {67 31} F9 {67 32} F9 {67 33} F21 {67 34} Console_21 {67 35} Console_33 {67 36} F33 {67 37} F45 {67 38} Console_21 {67 39} Console_33 {67 40} Console_9 {67 41} Console_21 {67 42} F9 {67 43} F9 {67 44} Console_9 {67 45} Console_21 {67 46} F9 {67 47} F9 {67 48} F9 {67 49} F21 {67 50} Console_21 {67 51} Console_33 {67 52} F33 {67 53} F45 {67 54} Console_21 {67 55} Console_33 {67 56} Console_9 {67 57} Console_21 {67 58} F9 {67 59} F9 {67 60} Console_9 {67 61} Console_21 {67 62} F9 {67 63} F9 {67 64} F9 {67 65} F21 {67 66} Console_21 {67 67} Console_33 {67 68} F33 {67 69} F45 {67 70} Console_21 {67 71} Console_33 {67 72} Console_9 {67 73} Console_21 {67 74} F9 {67 75} F9 {67 76} Console_9 {67 77} Console_21 {67 78} F9 {67 79} F9 {67 80} F9 {67 81} F21 {67 82} Console_21 {67 83} Console_33 {67 84} F33 {67 85} F45 {67 86} Console_21 {67 87} Console_33 {67 88} Console_9 {67 89} Console_21 {67 90} F9 {67 91} F9 {67 92} Console_9 {67 93} Console_21 {67 94} F9 {67 95} F9 {67 96} F9 {67 97} F21 {67 98} Console_21 {67 99} Console_33 {67 100} F33 {67 101} F45 {67 102} Console_21 {67 103} Console_33 {67 104} Console_9 {67 105} Console_21 {67 106} F9 {67 107} F9 {67 108} Console_9 {67 109} Console_21 {67 110} F9 {67 111} F9 {67 112} F9 {67 113} F21 {67 114} Console_21 {67 115} Console_33 {67 116} F33 {67 117} F45 {67 118} Console_21 {67 119} Console_33 {67 120} Console_9 {67 121} Console_21 {67 122} F9 {67 123} F9 {67 124} Console_9 {67 125} Console_21 {67 126} F9 {67 127} F9 {68 0} F10 {68 1} F22 {68 2} Console_22 {68 3} Console_34 {68 4} F34 {68 5} F46 {68 6} Console_22 {68 7} Console_34 {68 8} Console_10 {68 9} Console_22 {68 10} F10 {68 11} F10 {68 12} Console_10 {68 13} Console_22 {68 14} F10 {68 15} F10 {68 16} F10 {68 17} F22 {68 18} Console_22 {68 19} Console_34 {68 20} F34 {68 21} F46 {68 22} Console_22 {68 23} Console_34 {68 24} Console_10 {68 25} Console_22 {68 26} F10 {68 27} F10 {68 28} Console_10 {68 29} Console_22 {68 30} F10 {68 31} F10 {68 32} F10 {68 33} F22 {68 34} Console_22 {68 35} Console_34 {68 36} F34 {68 37} F46 {68 38} Console_22 {68 39} Console_34 {68 40} Console_10 {68 41} Console_22 {68 42} F10 {68 43} F10 {68 44} Console_10 {68 45} Console_22 {68 46} F10 {68 47} F10 {68 48} F10 {68 49} F22 {68 50} Console_22 {68 51} Console_34 {68 52} F34 {68 53} F46 {68 54} Console_22 {68 55} Console_34 {68 56} Console_10 {68 57} Console_22 {68 58} F10 {68 59} F10 {68 60} Console_10 {68 61} Console_22 {68 62} F10 {68 63} F10 {68 64} F10 {68 65} F22 {68 66} Console_22 {68 67} Console_34 {68 68} F34 {68 69} F46 {68 70} Console_22 {68 71} Console_34 {68 72} Console_10 {68 73} Console_22 {68 74} F10 {68 75} F10 {68 76} Console_10 {68 77} Console_22 {68 78} F10 {68 79} F10 {68 80} F10 {68 81} F22 {68 82} Console_22 {68 83} Console_34 {68 84} F34 {68 85} F46 {68 86} Console_22 {68 87} Console_34 {68 88} Console_10 {68 89} Console_22 {68 90} F10 {68 91} F10 {68 92} Console_10 {68 93} Console_22 {68 94} F10 {68 95} F10 {68 96} F10 {68 97} F22 {68 98} Console_22 {68 99} Console_34 {68 100} F34 {68 101} F46 {68 102} Console_22 {68 103} Console_34 {68 104} Console_10 {68 105} Console_22 {68 106} F10 {68 107} F10 {68 108} Console_10 {68 109} Console_22 {68 110} F10 {68 111} F10 {68 112} F10 {68 113} F22 {68 114} Console_22 {68 115} Console_34 {68 116} F34 {68 117} F46 {68 118} Console_22 {68 119} Console_34 {68 120} Console_10 {68 121} Console_22 {68 122} F10 {68 123} F10 {68 124} Console_10 {68 125} Console_22 {68 126} F10 {68 127} F10 {69 0} Num_Lock {69 1} Num_Lock {69 2} Hex_A {69 3} Num_Lock {69 4} Num_Lock {69 5} Num_Lock {69 6} Num_Lock {69 7} Num_Lock {69 8} Num_Lock {69 9} Hex_A {69 10} Num_Lock {69 11} Num_Lock {69 12} Num_Lock {69 13} Num_Lock {69 14} Num_Lock {69 15} Num_Lock {69 16} Num_Lock {69 17} Num_Lock {69 18} Hex_A {69 19} Num_Lock {69 20} Num_Lock {69 21} Num_Lock {69 22} Num_Lock {69 23} Num_Lock {69 24} Num_Lock {69 25} Hex_A {69 26} Num_Lock {69 27} Num_Lock {69 28} Num_Lock {69 29} Num_Lock {69 30} Num_Lock {69 31} Num_Lock {69 32} Num_Lock {69 33} Num_Lock {69 34} Hex_A {69 35} Num_Lock {69 36} Num_Lock {69 37} Num_Lock {69 38} Num_Lock {69 39} Num_Lock {69 40} Num_Lock {69 41} Hex_A {69 42} Num_Lock {69 43} Num_Lock {69 44} Num_Lock {69 45} Num_Lock {69 46} Num_Lock {69 47} Num_Lock {69 48} Num_Lock {69 49} Num_Lock {69 50} Hex_A {69 51} Num_Lock {69 52} Num_Lock {69 53} Num_Lock {69 54} Num_Lock {69 55} Num_Lock {69 56} Num_Lock {69 57} Hex_A {69 58} Num_Lock {69 59} Num_Lock {69 60} Num_Lock {69 61} Num_Lock {69 62} Num_Lock {69 63} Num_Lock {69 64} Num_Lock {69 65} Num_Lock {69 66} Hex_A {69 67} Num_Lock {69 68} Num_Lock {69 69} Num_Lock {69 70} Num_Lock {69 71} Num_Lock {69 72} Num_Lock {69 73} Hex_A {69 74} Num_Lock {69 75} Num_Lock {69 76} Num_Lock {69 77} Num_Lock {69 78} Num_Lock {69 79} Num_Lock {69 80} Num_Lock {69 81} Num_Lock {69 82} Hex_A {69 83} Num_Lock {69 84} Num_Lock {69 85} Num_Lock {69 86} Num_Lock {69 87} Num_Lock {69 88} Num_Lock {69 89} Hex_A {69 90} Num_Lock {69 91} Num_Lock {69 92} Num_Lock {69 93} Num_Lock {69 94} Num_Lock {69 95} Num_Lock {69 96} Num_Lock {69 97} Num_Lock {69 98} Hex_A {69 99} Num_Lock {69 100} Num_Lock {69 101} Num_Lock {69 102} Num_Lock {69 103} Num_Lock {69 104} Num_Lock {69 105} Hex_A {69 106} Num_Lock {69 107} Num_Lock {69 108} Num_Lock {69 109} Num_Lock {69 110} Num_Lock {69 111} Num_Lock {69 112} Num_Lock {69 113} Num_Lock {69 114} Hex_A {69 115} Num_Lock {69 116} Num_Lock {69 117} Num_Lock {69 118} Num_Lock {69 119} Num_Lock {69 120} Num_Lock {69 121} Hex_A {69 122} Num_Lock {69 123} Num_Lock {69 124} Num_Lock {69 125} Num_Lock {69 126} Num_Lock {69 127} Num_Lock {70 0} Scroll_Lock {70 1} Show_Memory {70 2} Show_Registers {70 3} Scroll_Lock {70 4} Show_State {70 5} Scroll_Lock {70 6} Scroll_Lock {70 7} Scroll_Lock {70 8} Show_Registers {70 9} Scroll_Lock {70 10} Scroll_Lock {70 11} Scroll_Lock {70 12} Scroll_Lock {70 13} Scroll_Lock {70 14} Scroll_Lock {70 15} Scroll_Lock {70 16} Scroll_Lock {70 17} Show_Memory {70 18} Show_Registers {70 19} Scroll_Lock {70 20} Show_State {70 21} Scroll_Lock {70 22} Scroll_Lock {70 23} Scroll_Lock {70 24} Show_Registers {70 25} Scroll_Lock {70 26} Scroll_Lock {70 27} Scroll_Lock {70 28} Scroll_Lock {70 29} Scroll_Lock {70 30} Scroll_Lock {70 31} Scroll_Lock {70 32} Scroll_Lock {70 33} Show_Memory {70 34} Show_Registers {70 35} Scroll_Lock {70 36} Show_State {70 37} Scroll_Lock {70 38} Scroll_Lock {70 39} Scroll_Lock {70 40} Show_Registers {70 41} Scroll_Lock {70 42} Scroll_Lock {70 43} Scroll_Lock {70 44} Scroll_Lock {70 45} Scroll_Lock {70 46} Scroll_Lock {70 47} Scroll_Lock {70 48} Scroll_Lock {70 49} Show_Memory {70 50} Show_Registers {70 51} Scroll_Lock {70 52} Show_State {70 53} Scroll_Lock {70 54} Scroll_Lock {70 55} Scroll_Lock {70 56} Show_Registers {70 57} Scroll_Lock {70 58} Scroll_Lock {70 59} Scroll_Lock {70 60} Scroll_Lock {70 61} Scroll_Lock {70 62} Scroll_Lock {70 63} Scroll_Lock {70 64} Scroll_Lock {70 65} Show_Memory {70 66} Show_Registers {70 67} Scroll_Lock {70 68} Show_State {70 69} Scroll_Lock {70 70} Scroll_Lock {70 71} Scroll_Lock {70 72} Show_Registers {70 73} Scroll_Lock {70 74} Scroll_Lock {70 75} Scroll_Lock {70 76} Scroll_Lock {70 77} Scroll_Lock {70 78} Scroll_Lock {70 79} Scroll_Lock {70 80} Scroll_Lock {70 81} Show_Memory {70 82} Show_Registers {70 83} Scroll_Lock {70 84} Show_State {70 85} Scroll_Lock {70 86} Scroll_Lock {70 87} Scroll_Lock {70 88} Show_Registers {70 89} Scroll_Lock {70 90} Scroll_Lock {70 91} Scroll_Lock {70 92} Scroll_Lock {70 93} Scroll_Lock {70 94} Scroll_Lock {70 95} Scroll_Lock {70 96} Scroll_Lock {70 97} Show_Memory {70 98} Show_Registers {70 99} Scroll_Lock {70 100} Show_State {70 101} Scroll_Lock {70 102} Scroll_Lock {70 103} Scroll_Lock {70 104} Show_Registers {70 105} Scroll_Lock {70 106} Scroll_Lock {70 107} Scroll_Lock {70 108} Scroll_Lock {70 109} Scroll_Lock {70 110} Scroll_Lock {70 111} Scroll_Lock {70 112} Scroll_Lock {70 113} Show_Memory {70 114} Show_Registers {70 115} Scroll_Lock {70 116} Show_State {70 117} Scroll_Lock {70 118} Scroll_Lock {70 119} Scroll_Lock {70 120} Show_Registers {70 121} Scroll_Lock {70 122} Scroll_Lock {70 123} Scroll_Lock {70 124} Scroll_Lock {70 125} Scroll_Lock {70 126} Scroll_Lock {70 127} Scroll_Lock {71 0} KP_7 {71 1} KP_7 {71 2} Hex_7 {71 3} KP_7 {71 4} KP_7 {71 5} KP_7 {71 6} KP_7 {71 7} KP_7 {71 8} Ascii_7 {71 9} Hex_7 {71 10} KP_7 {71 11} KP_7 {71 12} KP_7 {71 13} KP_7 {71 14} KP_7 {71 15} KP_7 {71 16} KP_7 {71 17} KP_7 {71 18} Hex_7 {71 19} KP_7 {71 20} KP_7 {71 21} KP_7 {71 22} KP_7 {71 23} KP_7 {71 24} Ascii_7 {71 25} Hex_7 {71 26} KP_7 {71 27} KP_7 {71 28} KP_7 {71 29} KP_7 {71 30} KP_7 {71 31} KP_7 {71 32} KP_7 {71 33} KP_7 {71 34} Hex_7 {71 35} KP_7 {71 36} KP_7 {71 37} KP_7 {71 38} KP_7 {71 39} KP_7 {71 40} Ascii_7 {71 41} Hex_7 {71 42} KP_7 {71 43} KP_7 {71 44} KP_7 {71 45} KP_7 {71 46} KP_7 {71 47} KP_7 {71 48} KP_7 {71 49} KP_7 {71 50} Hex_7 {71 51} KP_7 {71 52} KP_7 {71 53} KP_7 {71 54} KP_7 {71 55} KP_7 {71 56} Ascii_7 {71 57} Hex_7 {71 58} KP_7 {71 59} KP_7 {71 60} KP_7 {71 61} KP_7 {71 62} KP_7 {71 63} KP_7 {71 64} KP_7 {71 65} KP_7 {71 66} Hex_7 {71 67} KP_7 {71 68} KP_7 {71 69} KP_7 {71 70} KP_7 {71 71} KP_7 {71 72} Ascii_7 {71 73} Hex_7 {71 74} KP_7 {71 75} KP_7 {71 76} KP_7 {71 77} KP_7 {71 78} KP_7 {71 79} KP_7 {71 80} KP_7 {71 81} KP_7 {71 82} Hex_7 {71 83} KP_7 {71 84} KP_7 {71 85} KP_7 {71 86} KP_7 {71 87} KP_7 {71 88} Ascii_7 {71 89} Hex_7 {71 90} KP_7 {71 91} KP_7 {71 92} KP_7 {71 93} KP_7 {71 94} KP_7 {71 95} KP_7 {71 96} KP_7 {71 97} KP_7 {71 98} Hex_7 {71 99} KP_7 {71 100} KP_7 {71 101} KP_7 {71 102} KP_7 {71 103} KP_7 {71 104} Ascii_7 {71 105} Hex_7 {71 106} KP_7 {71 107} KP_7 {71 108} KP_7 {71 109} KP_7 {71 110} KP_7 {71 111} KP_7 {71 112} KP_7 {71 113} KP_7 {71 114} Hex_7 {71 115} KP_7 {71 116} KP_7 {71 117} KP_7 {71 118} KP_7 {71 119} KP_7 {71 120} Ascii_7 {71 121} Hex_7 {71 122} KP_7 {71 123} KP_7 {71 124} KP_7 {71 125} KP_7 {71 126} KP_7 {71 127} KP_7 {72 0} KP_8 {72 1} KP_8 {72 2} Hex_8 {72 3} KP_8 {72 4} KP_8 {72 5} KP_8 {72 6} KP_8 {72 7} KP_8 {72 8} Ascii_8 {72 9} Hex_8 {72 10} KP_8 {72 11} KP_8 {72 12} KP_8 {72 13} KP_8 {72 14} KP_8 {72 15} KP_8 {72 16} KP_8 {72 17} KP_8 {72 18} Hex_8 {72 19} KP_8 {72 20} KP_8 {72 21} KP_8 {72 22} KP_8 {72 23} KP_8 {72 24} Ascii_8 {72 25} Hex_8 {72 26} KP_8 {72 27} KP_8 {72 28} KP_8 {72 29} KP_8 {72 30} KP_8 {72 31} KP_8 {72 32} KP_8 {72 33} KP_8 {72 34} Hex_8 {72 35} KP_8 {72 36} KP_8 {72 37} KP_8 {72 38} KP_8 {72 39} KP_8 {72 40} Ascii_8 {72 41} Hex_8 {72 42} KP_8 {72 43} KP_8 {72 44} KP_8 {72 45} KP_8 {72 46} KP_8 {72 47} KP_8 {72 48} KP_8 {72 49} KP_8 {72 50} Hex_8 {72 51} KP_8 {72 52} KP_8 {72 53} KP_8 {72 54} KP_8 {72 55} KP_8 {72 56} Ascii_8 {72 57} Hex_8 {72 58} KP_8 {72 59} KP_8 {72 60} KP_8 {72 61} KP_8 {72 62} KP_8 {72 63} KP_8 {72 64} KP_8 {72 65} KP_8 {72 66} Hex_8 {72 67} KP_8 {72 68} KP_8 {72 69} KP_8 {72 70} KP_8 {72 71} KP_8 {72 72} Ascii_8 {72 73} Hex_8 {72 74} KP_8 {72 75} KP_8 {72 76} KP_8 {72 77} KP_8 {72 78} KP_8 {72 79} KP_8 {72 80} KP_8 {72 81} KP_8 {72 82} Hex_8 {72 83} KP_8 {72 84} KP_8 {72 85} KP_8 {72 86} KP_8 {72 87} KP_8 {72 88} Ascii_8 {72 89} Hex_8 {72 90} KP_8 {72 91} KP_8 {72 92} KP_8 {72 93} KP_8 {72 94} KP_8 {72 95} KP_8 {72 96} KP_8 {72 97} KP_8 {72 98} Hex_8 {72 99} KP_8 {72 100} KP_8 {72 101} KP_8 {72 102} KP_8 {72 103} KP_8 {72 104} Ascii_8 {72 105} Hex_8 {72 106} KP_8 {72 107} KP_8 {72 108} KP_8 {72 109} KP_8 {72 110} KP_8 {72 111} KP_8 {72 112} KP_8 {72 113} KP_8 {72 114} Hex_8 {72 115} KP_8 {72 116} KP_8 {72 117} KP_8 {72 118} KP_8 {72 119} KP_8 {72 120} Ascii_8 {72 121} Hex_8 {72 122} KP_8 {72 123} KP_8 {72 124} KP_8 {72 125} KP_8 {72 126} KP_8 {72 127} KP_8 {73 0} KP_9 {73 1} KP_9 {73 2} Hex_9 {73 3} KP_9 {73 4} KP_9 {73 5} KP_9 {73 6} KP_9 {73 7} KP_9 {73 8} Ascii_9 {73 9} Hex_9 {73 10} KP_9 {73 11} KP_9 {73 12} KP_9 {73 13} KP_9 {73 14} KP_9 {73 15} KP_9 {73 16} KP_9 {73 17} KP_9 {73 18} Hex_9 {73 19} KP_9 {73 20} KP_9 {73 21} KP_9 {73 22} KP_9 {73 23} KP_9 {73 24} Ascii_9 {73 25} Hex_9 {73 26} KP_9 {73 27} KP_9 {73 28} KP_9 {73 29} KP_9 {73 30} KP_9 {73 31} KP_9 {73 32} KP_9 {73 33} KP_9 {73 34} Hex_9 {73 35} KP_9 {73 36} KP_9 {73 37} KP_9 {73 38} KP_9 {73 39} KP_9 {73 40} Ascii_9 {73 41} Hex_9 {73 42} KP_9 {73 43} KP_9 {73 44} KP_9 {73 45} KP_9 {73 46} KP_9 {73 47} KP_9 {73 48} KP_9 {73 49} KP_9 {73 50} Hex_9 {73 51} KP_9 {73 52} KP_9 {73 53} KP_9 {73 54} KP_9 {73 55} KP_9 {73 56} Ascii_9 {73 57} Hex_9 {73 58} KP_9 {73 59} KP_9 {73 60} KP_9 {73 61} KP_9 {73 62} KP_9 {73 63} KP_9 {73 64} KP_9 {73 65} KP_9 {73 66} Hex_9 {73 67} KP_9 {73 68} KP_9 {73 69} KP_9 {73 70} KP_9 {73 71} KP_9 {73 72} Ascii_9 {73 73} Hex_9 {73 74} KP_9 {73 75} KP_9 {73 76} KP_9 {73 77} KP_9 {73 78} KP_9 {73 79} KP_9 {73 80} KP_9 {73 81} KP_9 {73 82} Hex_9 {73 83} KP_9 {73 84} KP_9 {73 85} KP_9 {73 86} KP_9 {73 87} KP_9 {73 88} Ascii_9 {73 89} Hex_9 {73 90} KP_9 {73 91} KP_9 {73 92} KP_9 {73 93} KP_9 {73 94} KP_9 {73 95} KP_9 {73 96} KP_9 {73 97} KP_9 {73 98} Hex_9 {73 99} KP_9 {73 100} KP_9 {73 101} KP_9 {73 102} KP_9 {73 103} KP_9 {73 104} Ascii_9 {73 105} Hex_9 {73 106} KP_9 {73 107} KP_9 {73 108} KP_9 {73 109} KP_9 {73 110} KP_9 {73 111} KP_9 {73 112} KP_9 {73 113} KP_9 {73 114} Hex_9 {73 115} KP_9 {73 116} KP_9 {73 117} KP_9 {73 118} KP_9 {73 119} KP_9 {73 120} Ascii_9 {73 121} Hex_9 {73 122} KP_9 {73 123} KP_9 {73 124} KP_9 {73 125} KP_9 {73 126} KP_9 {73 127} KP_9 {74 0} KP_Subtract {74 1} KP_Subtract {74 2} Hex_D {74 3} KP_Subtract {74 4} KP_Subtract {74 5} KP_Subtract {74 6} KP_Subtract {74 7} KP_Subtract {74 8} KP_Subtract {74 9} Hex_D {74 10} KP_Subtract {74 11} KP_Subtract {74 12} KP_Subtract {74 13} KP_Subtract {74 14} KP_Subtract {74 15} KP_Subtract {74 16} KP_Subtract {74 17} KP_Subtract {74 18} Hex_D {74 19} KP_Subtract {74 20} KP_Subtract {74 21} KP_Subtract {74 22} KP_Subtract {74 23} KP_Subtract {74 24} KP_Subtract {74 25} Hex_D {74 26} KP_Subtract {74 27} KP_Subtract {74 28} KP_Subtract {74 29} KP_Subtract {74 30} KP_Subtract {74 31} KP_Subtract {74 32} KP_Subtract {74 33} KP_Subtract {74 34} Hex_D {74 35} KP_Subtract {74 36} KP_Subtract {74 37} KP_Subtract {74 38} KP_Subtract {74 39} KP_Subtract {74 40} KP_Subtract {74 41} Hex_D {74 42} KP_Subtract {74 43} KP_Subtract {74 44} KP_Subtract {74 45} KP_Subtract {74 46} KP_Subtract {74 47} KP_Subtract {74 48} KP_Subtract {74 49} KP_Subtract {74 50} Hex_D {74 51} KP_Subtract {74 52} KP_Subtract {74 53} KP_Subtract {74 54} KP_Subtract {74 55} KP_Subtract {74 56} KP_Subtract {74 57} Hex_D {74 58} KP_Subtract {74 59} KP_Subtract {74 60} KP_Subtract {74 61} KP_Subtract {74 62} KP_Subtract {74 63} KP_Subtract {74 64} KP_Subtract {74 65} KP_Subtract {74 66} Hex_D {74 67} KP_Subtract {74 68} KP_Subtract {74 69} KP_Subtract {74 70} KP_Subtract {74 71} KP_Subtract {74 72} KP_Subtract {74 73} Hex_D {74 74} KP_Subtract {74 75} KP_Subtract {74 76} KP_Subtract {74 77} KP_Subtract {74 78} KP_Subtract {74 79} KP_Subtract {74 80} KP_Subtract {74 81} KP_Subtract {74 82} Hex_D {74 83} KP_Subtract {74 84} KP_Subtract {74 85} KP_Subtract {74 86} KP_Subtract {74 87} KP_Subtract {74 88} KP_Subtract {74 89} Hex_D {74 90} KP_Subtract {74 91} KP_Subtract {74 92} KP_Subtract {74 93} KP_Subtract {74 94} KP_Subtract {74 95} KP_Subtract {74 96} KP_Subtract {74 97} KP_Subtract {74 98} Hex_D {74 99} KP_Subtract {74 100} KP_Subtract {74 101} KP_Subtract {74 102} KP_Subtract {74 103} KP_Subtract {74 104} KP_Subtract {74 105} Hex_D {74 106} KP_Subtract {74 107} KP_Subtract {74 108} KP_Subtract {74 109} KP_Subtract {74 110} KP_Subtract {74 111} KP_Subtract {74 112} KP_Subtract {74 113} KP_Subtract {74 114} Hex_D {74 115} KP_Subtract {74 116} KP_Subtract {74 117} KP_Subtract {74 118} KP_Subtract {74 119} KP_Subtract {74 120} KP_Subtract {74 121} Hex_D {74 122} KP_Subtract {74 123} KP_Subtract {74 124} KP_Subtract {74 125} KP_Subtract {74 126} KP_Subtract {74 127} KP_Subtract {75 0} KP_4 {75 1} KP_4 {75 2} Hex_4 {75 3} KP_4 {75 4} KP_4 {75 5} KP_4 {75 6} KP_4 {75 7} KP_4 {75 8} Ascii_4 {75 9} Hex_4 {75 10} KP_4 {75 11} KP_4 {75 12} KP_4 {75 13} KP_4 {75 14} KP_4 {75 15} KP_4 {75 16} KP_4 {75 17} KP_4 {75 18} Hex_4 {75 19} KP_4 {75 20} KP_4 {75 21} KP_4 {75 22} KP_4 {75 23} KP_4 {75 24} Ascii_4 {75 25} Hex_4 {75 26} KP_4 {75 27} KP_4 {75 28} KP_4 {75 29} KP_4 {75 30} KP_4 {75 31} KP_4 {75 32} KP_4 {75 33} KP_4 {75 34} Hex_4 {75 35} KP_4 {75 36} KP_4 {75 37} KP_4 {75 38} KP_4 {75 39} KP_4 {75 40} Ascii_4 {75 41} Hex_4 {75 42} KP_4 {75 43} KP_4 {75 44} KP_4 {75 45} KP_4 {75 46} KP_4 {75 47} KP_4 {75 48} KP_4 {75 49} KP_4 {75 50} Hex_4 {75 51} KP_4 {75 52} KP_4 {75 53} KP_4 {75 54} KP_4 {75 55} KP_4 {75 56} Ascii_4 {75 57} Hex_4 {75 58} KP_4 {75 59} KP_4 {75 60} KP_4 {75 61} KP_4 {75 62} KP_4 {75 63} KP_4 {75 64} KP_4 {75 65} KP_4 {75 66} Hex_4 {75 67} KP_4 {75 68} KP_4 {75 69} KP_4 {75 70} KP_4 {75 71} KP_4 {75 72} Ascii_4 {75 73} Hex_4 {75 74} KP_4 {75 75} KP_4 {75 76} KP_4 {75 77} KP_4 {75 78} KP_4 {75 79} KP_4 {75 80} KP_4 {75 81} KP_4 {75 82} Hex_4 {75 83} KP_4 {75 84} KP_4 {75 85} KP_4 {75 86} KP_4 {75 87} KP_4 {75 88} Ascii_4 {75 89} Hex_4 {75 90} KP_4 {75 91} KP_4 {75 92} KP_4 {75 93} KP_4 {75 94} KP_4 {75 95} KP_4 {75 96} KP_4 {75 97} KP_4 {75 98} Hex_4 {75 99} KP_4 {75 100} KP_4 {75 101} KP_4 {75 102} KP_4 {75 103} KP_4 {75 104} Ascii_4 {75 105} Hex_4 {75 106} KP_4 {75 107} KP_4 {75 108} KP_4 {75 109} KP_4 {75 110} KP_4 {75 111} KP_4 {75 112} KP_4 {75 113} KP_4 {75 114} Hex_4 {75 115} KP_4 {75 116} KP_4 {75 117} KP_4 {75 118} KP_4 {75 119} KP_4 {75 120} Ascii_4 {75 121} Hex_4 {75 122} KP_4 {75 123} KP_4 {75 124} KP_4 {75 125} KP_4 {75 126} KP_4 {75 127} KP_4 {76 0} KP_5 {76 1} KP_5 {76 2} Hex_5 {76 3} KP_5 {76 4} KP_5 {76 5} KP_5 {76 6} KP_5 {76 7} KP_5 {76 8} Ascii_5 {76 9} Hex_5 {76 10} KP_5 {76 11} KP_5 {76 12} KP_5 {76 13} KP_5 {76 14} KP_5 {76 15} KP_5 {76 16} KP_5 {76 17} KP_5 {76 18} Hex_5 {76 19} KP_5 {76 20} KP_5 {76 21} KP_5 {76 22} KP_5 {76 23} KP_5 {76 24} Ascii_5 {76 25} Hex_5 {76 26} KP_5 {76 27} KP_5 {76 28} KP_5 {76 29} KP_5 {76 30} KP_5 {76 31} KP_5 {76 32} KP_5 {76 33} KP_5 {76 34} Hex_5 {76 35} KP_5 {76 36} KP_5 {76 37} KP_5 {76 38} KP_5 {76 39} KP_5 {76 40} Ascii_5 {76 41} Hex_5 {76 42} KP_5 {76 43} KP_5 {76 44} KP_5 {76 45} KP_5 {76 46} KP_5 {76 47} KP_5 {76 48} KP_5 {76 49} KP_5 {76 50} Hex_5 {76 51} KP_5 {76 52} KP_5 {76 53} KP_5 {76 54} KP_5 {76 55} KP_5 {76 56} Ascii_5 {76 57} Hex_5 {76 58} KP_5 {76 59} KP_5 {76 60} KP_5 {76 61} KP_5 {76 62} KP_5 {76 63} KP_5 {76 64} KP_5 {76 65} KP_5 {76 66} Hex_5 {76 67} KP_5 {76 68} KP_5 {76 69} KP_5 {76 70} KP_5 {76 71} KP_5 {76 72} Ascii_5 {76 73} Hex_5 {76 74} KP_5 {76 75} KP_5 {76 76} KP_5 {76 77} KP_5 {76 78} KP_5 {76 79} KP_5 {76 80} KP_5 {76 81} KP_5 {76 82} Hex_5 {76 83} KP_5 {76 84} KP_5 {76 85} KP_5 {76 86} KP_5 {76 87} KP_5 {76 88} Ascii_5 {76 89} Hex_5 {76 90} KP_5 {76 91} KP_5 {76 92} KP_5 {76 93} KP_5 {76 94} KP_5 {76 95} KP_5 {76 96} KP_5 {76 97} KP_5 {76 98} Hex_5 {76 99} KP_5 {76 100} KP_5 {76 101} KP_5 {76 102} KP_5 {76 103} KP_5 {76 104} Ascii_5 {76 105} Hex_5 {76 106} KP_5 {76 107} KP_5 {76 108} KP_5 {76 109} KP_5 {76 110} KP_5 {76 111} KP_5 {76 112} KP_5 {76 113} KP_5 {76 114} Hex_5 {76 115} KP_5 {76 116} KP_5 {76 117} KP_5 {76 118} KP_5 {76 119} KP_5 {76 120} Ascii_5 {76 121} Hex_5 {76 122} KP_5 {76 123} KP_5 {76 124} KP_5 {76 125} KP_5 {76 126} KP_5 {76 127} KP_5 {77 0} KP_6 {77 1} KP_6 {77 2} Hex_6 {77 3} KP_6 {77 4} KP_6 {77 5} KP_6 {77 6} KP_6 {77 7} KP_6 {77 8} Ascii_6 {77 9} Hex_6 {77 10} KP_6 {77 11} KP_6 {77 12} KP_6 {77 13} KP_6 {77 14} KP_6 {77 15} KP_6 {77 16} KP_6 {77 17} KP_6 {77 18} Hex_6 {77 19} KP_6 {77 20} KP_6 {77 21} KP_6 {77 22} KP_6 {77 23} KP_6 {77 24} Ascii_6 {77 25} Hex_6 {77 26} KP_6 {77 27} KP_6 {77 28} KP_6 {77 29} KP_6 {77 30} KP_6 {77 31} KP_6 {77 32} KP_6 {77 33} KP_6 {77 34} Hex_6 {77 35} KP_6 {77 36} KP_6 {77 37} KP_6 {77 38} KP_6 {77 39} KP_6 {77 40} Ascii_6 {77 41} Hex_6 {77 42} KP_6 {77 43} KP_6 {77 44} KP_6 {77 45} KP_6 {77 46} KP_6 {77 47} KP_6 {77 48} KP_6 {77 49} KP_6 {77 50} Hex_6 {77 51} KP_6 {77 52} KP_6 {77 53} KP_6 {77 54} KP_6 {77 55} KP_6 {77 56} Ascii_6 {77 57} Hex_6 {77 58} KP_6 {77 59} KP_6 {77 60} KP_6 {77 61} KP_6 {77 62} KP_6 {77 63} KP_6 {77 64} KP_6 {77 65} KP_6 {77 66} Hex_6 {77 67} KP_6 {77 68} KP_6 {77 69} KP_6 {77 70} KP_6 {77 71} KP_6 {77 72} Ascii_6 {77 73} Hex_6 {77 74} KP_6 {77 75} KP_6 {77 76} KP_6 {77 77} KP_6 {77 78} KP_6 {77 79} KP_6 {77 80} KP_6 {77 81} KP_6 {77 82} Hex_6 {77 83} KP_6 {77 84} KP_6 {77 85} KP_6 {77 86} KP_6 {77 87} KP_6 {77 88} Ascii_6 {77 89} Hex_6 {77 90} KP_6 {77 91} KP_6 {77 92} KP_6 {77 93} KP_6 {77 94} KP_6 {77 95} KP_6 {77 96} KP_6 {77 97} KP_6 {77 98} Hex_6 {77 99} KP_6 {77 100} KP_6 {77 101} KP_6 {77 102} KP_6 {77 103} KP_6 {77 104} Ascii_6 {77 105} Hex_6 {77 106} KP_6 {77 107} KP_6 {77 108} KP_6 {77 109} KP_6 {77 110} KP_6 {77 111} KP_6 {77 112} KP_6 {77 113} KP_6 {77 114} Hex_6 {77 115} KP_6 {77 116} KP_6 {77 117} KP_6 {77 118} KP_6 {77 119} KP_6 {77 120} Ascii_6 {77 121} Hex_6 {77 122} KP_6 {77 123} KP_6 {77 124} KP_6 {77 125} KP_6 {77 126} KP_6 {77 127} KP_6 {78 0} KP_Add {78 1} KP_Add {78 2} Hex_E {78 3} KP_Add {78 4} KP_Add {78 5} KP_Add {78 6} KP_Add {78 7} KP_Add {78 8} KP_Add {78 9} Hex_E {78 10} KP_Add {78 11} KP_Add {78 12} KP_Add {78 13} KP_Add {78 14} KP_Add {78 15} KP_Add {78 16} KP_Add {78 17} KP_Add {78 18} Hex_E {78 19} KP_Add {78 20} KP_Add {78 21} KP_Add {78 22} KP_Add {78 23} KP_Add {78 24} KP_Add {78 25} Hex_E {78 26} KP_Add {78 27} KP_Add {78 28} KP_Add {78 29} KP_Add {78 30} KP_Add {78 31} KP_Add {78 32} KP_Add {78 33} KP_Add {78 34} Hex_E {78 35} KP_Add {78 36} KP_Add {78 37} KP_Add {78 38} KP_Add {78 39} KP_Add {78 40} KP_Add {78 41} Hex_E {78 42} KP_Add {78 43} KP_Add {78 44} KP_Add {78 45} KP_Add {78 46} KP_Add {78 47} KP_Add {78 48} KP_Add {78 49} KP_Add {78 50} Hex_E {78 51} KP_Add {78 52} KP_Add {78 53} KP_Add {78 54} KP_Add {78 55} KP_Add {78 56} KP_Add {78 57} Hex_E {78 58} KP_Add {78 59} KP_Add {78 60} KP_Add {78 61} KP_Add {78 62} KP_Add {78 63} KP_Add {78 64} KP_Add {78 65} KP_Add {78 66} Hex_E {78 67} KP_Add {78 68} KP_Add {78 69} KP_Add {78 70} KP_Add {78 71} KP_Add {78 72} KP_Add {78 73} Hex_E {78 74} KP_Add {78 75} KP_Add {78 76} KP_Add {78 77} KP_Add {78 78} KP_Add {78 79} KP_Add {78 80} KP_Add {78 81} KP_Add {78 82} Hex_E {78 83} KP_Add {78 84} KP_Add {78 85} KP_Add {78 86} KP_Add {78 87} KP_Add {78 88} KP_Add {78 89} Hex_E {78 90} KP_Add {78 91} KP_Add {78 92} KP_Add {78 93} KP_Add {78 94} KP_Add {78 95} KP_Add {78 96} KP_Add {78 97} KP_Add {78 98} Hex_E {78 99} KP_Add {78 100} KP_Add {78 101} KP_Add {78 102} KP_Add {78 103} KP_Add {78 104} KP_Add {78 105} Hex_E {78 106} KP_Add {78 107} KP_Add {78 108} KP_Add {78 109} KP_Add {78 110} KP_Add {78 111} KP_Add {78 112} KP_Add {78 113} KP_Add {78 114} Hex_E {78 115} KP_Add {78 116} KP_Add {78 117} KP_Add {78 118} KP_Add {78 119} KP_Add {78 120} KP_Add {78 121} Hex_E {78 122} KP_Add {78 123} KP_Add {78 124} KP_Add {78 125} KP_Add {78 126} KP_Add {78 127} KP_Add {79 0} KP_1 {79 1} KP_1 {79 2} Hex_1 {79 3} KP_1 {79 4} KP_1 {79 5} KP_1 {79 6} KP_1 {79 7} KP_1 {79 8} Ascii_1 {79 9} Hex_1 {79 10} KP_1 {79 11} KP_1 {79 12} KP_1 {79 13} KP_1 {79 14} KP_1 {79 15} KP_1 {79 16} KP_1 {79 17} KP_1 {79 18} Hex_1 {79 19} KP_1 {79 20} KP_1 {79 21} KP_1 {79 22} KP_1 {79 23} KP_1 {79 24} Ascii_1 {79 25} Hex_1 {79 26} KP_1 {79 27} KP_1 {79 28} KP_1 {79 29} KP_1 {79 30} KP_1 {79 31} KP_1 {79 32} KP_1 {79 33} KP_1 {79 34} Hex_1 {79 35} KP_1 {79 36} KP_1 {79 37} KP_1 {79 38} KP_1 {79 39} KP_1 {79 40} Ascii_1 {79 41} Hex_1 {79 42} KP_1 {79 43} KP_1 {79 44} KP_1 {79 45} KP_1 {79 46} KP_1 {79 47} KP_1 {79 48} KP_1 {79 49} KP_1 {79 50} Hex_1 {79 51} KP_1 {79 52} KP_1 {79 53} KP_1 {79 54} KP_1 {79 55} KP_1 {79 56} Ascii_1 {79 57} Hex_1 {79 58} KP_1 {79 59} KP_1 {79 60} KP_1 {79 61} KP_1 {79 62} KP_1 {79 63} KP_1 {79 64} KP_1 {79 65} KP_1 {79 66} Hex_1 {79 67} KP_1 {79 68} KP_1 {79 69} KP_1 {79 70} KP_1 {79 71} KP_1 {79 72} Ascii_1 {79 73} Hex_1 {79 74} KP_1 {79 75} KP_1 {79 76} KP_1 {79 77} KP_1 {79 78} KP_1 {79 79} KP_1 {79 80} KP_1 {79 81} KP_1 {79 82} Hex_1 {79 83} KP_1 {79 84} KP_1 {79 85} KP_1 {79 86} KP_1 {79 87} KP_1 {79 88} Ascii_1 {79 89} Hex_1 {79 90} KP_1 {79 91} KP_1 {79 92} KP_1 {79 93} KP_1 {79 94} KP_1 {79 95} KP_1 {79 96} KP_1 {79 97} KP_1 {79 98} Hex_1 {79 99} KP_1 {79 100} KP_1 {79 101} KP_1 {79 102} KP_1 {79 103} KP_1 {79 104} Ascii_1 {79 105} Hex_1 {79 106} KP_1 {79 107} KP_1 {79 108} KP_1 {79 109} KP_1 {79 110} KP_1 {79 111} KP_1 {79 112} KP_1 {79 113} KP_1 {79 114} Hex_1 {79 115} KP_1 {79 116} KP_1 {79 117} KP_1 {79 118} KP_1 {79 119} KP_1 {79 120} Ascii_1 {79 121} Hex_1 {79 122} KP_1 {79 123} KP_1 {79 124} KP_1 {79 125} KP_1 {79 126} KP_1 {79 127} KP_1 {80 0} KP_2 {80 1} KP_2 {80 2} Hex_2 {80 3} KP_2 {80 4} KP_2 {80 5} KP_2 {80 6} KP_2 {80 7} KP_2 {80 8} Ascii_2 {80 9} Hex_2 {80 10} KP_2 {80 11} KP_2 {80 12} KP_2 {80 13} KP_2 {80 14} KP_2 {80 15} KP_2 {80 16} KP_2 {80 17} KP_2 {80 18} Hex_2 {80 19} KP_2 {80 20} KP_2 {80 21} KP_2 {80 22} KP_2 {80 23} KP_2 {80 24} Ascii_2 {80 25} Hex_2 {80 26} KP_2 {80 27} KP_2 {80 28} KP_2 {80 29} KP_2 {80 30} KP_2 {80 31} KP_2 {80 32} KP_2 {80 33} KP_2 {80 34} Hex_2 {80 35} KP_2 {80 36} KP_2 {80 37} KP_2 {80 38} KP_2 {80 39} KP_2 {80 40} Ascii_2 {80 41} Hex_2 {80 42} KP_2 {80 43} KP_2 {80 44} KP_2 {80 45} KP_2 {80 46} KP_2 {80 47} KP_2 {80 48} KP_2 {80 49} KP_2 {80 50} Hex_2 {80 51} KP_2 {80 52} KP_2 {80 53} KP_2 {80 54} KP_2 {80 55} KP_2 {80 56} Ascii_2 {80 57} Hex_2 {80 58} KP_2 {80 59} KP_2 {80 60} KP_2 {80 61} KP_2 {80 62} KP_2 {80 63} KP_2 {80 64} KP_2 {80 65} KP_2 {80 66} Hex_2 {80 67} KP_2 {80 68} KP_2 {80 69} KP_2 {80 70} KP_2 {80 71} KP_2 {80 72} Ascii_2 {80 73} Hex_2 {80 74} KP_2 {80 75} KP_2 {80 76} KP_2 {80 77} KP_2 {80 78} KP_2 {80 79} KP_2 {80 80} KP_2 {80 81} KP_2 {80 82} Hex_2 {80 83} KP_2 {80 84} KP_2 {80 85} KP_2 {80 86} KP_2 {80 87} KP_2 {80 88} Ascii_2 {80 89} Hex_2 {80 90} KP_2 {80 91} KP_2 {80 92} KP_2 {80 93} KP_2 {80 94} KP_2 {80 95} KP_2 {80 96} KP_2 {80 97} KP_2 {80 98} Hex_2 {80 99} KP_2 {80 100} KP_2 {80 101} KP_2 {80 102} KP_2 {80 103} KP_2 {80 104} Ascii_2 {80 105} Hex_2 {80 106} KP_2 {80 107} KP_2 {80 108} KP_2 {80 109} KP_2 {80 110} KP_2 {80 111} KP_2 {80 112} KP_2 {80 113} KP_2 {80 114} Hex_2 {80 115} KP_2 {80 116} KP_2 {80 117} KP_2 {80 118} KP_2 {80 119} KP_2 {80 120} Ascii_2 {80 121} Hex_2 {80 122} KP_2 {80 123} KP_2 {80 124} KP_2 {80 125} KP_2 {80 126} KP_2 {80 127} KP_2 {81 0} KP_3 {81 1} KP_3 {81 2} Hex_3 {81 3} KP_3 {81 4} KP_3 {81 5} KP_3 {81 6} KP_3 {81 7} KP_3 {81 8} Ascii_3 {81 9} Hex_3 {81 10} KP_3 {81 11} KP_3 {81 12} KP_3 {81 13} KP_3 {81 14} KP_3 {81 15} KP_3 {81 16} KP_3 {81 17} KP_3 {81 18} Hex_3 {81 19} KP_3 {81 20} KP_3 {81 21} KP_3 {81 22} KP_3 {81 23} KP_3 {81 24} Ascii_3 {81 25} Hex_3 {81 26} KP_3 {81 27} KP_3 {81 28} KP_3 {81 29} KP_3 {81 30} KP_3 {81 31} KP_3 {81 32} KP_3 {81 33} KP_3 {81 34} Hex_3 {81 35} KP_3 {81 36} KP_3 {81 37} KP_3 {81 38} KP_3 {81 39} KP_3 {81 40} Ascii_3 {81 41} Hex_3 {81 42} KP_3 {81 43} KP_3 {81 44} KP_3 {81 45} KP_3 {81 46} KP_3 {81 47} KP_3 {81 48} KP_3 {81 49} KP_3 {81 50} Hex_3 {81 51} KP_3 {81 52} KP_3 {81 53} KP_3 {81 54} KP_3 {81 55} KP_3 {81 56} Ascii_3 {81 57} Hex_3 {81 58} KP_3 {81 59} KP_3 {81 60} KP_3 {81 61} KP_3 {81 62} KP_3 {81 63} KP_3 {81 64} KP_3 {81 65} KP_3 {81 66} Hex_3 {81 67} KP_3 {81 68} KP_3 {81 69} KP_3 {81 70} KP_3 {81 71} KP_3 {81 72} Ascii_3 {81 73} Hex_3 {81 74} KP_3 {81 75} KP_3 {81 76} KP_3 {81 77} KP_3 {81 78} KP_3 {81 79} KP_3 {81 80} KP_3 {81 81} KP_3 {81 82} Hex_3 {81 83} KP_3 {81 84} KP_3 {81 85} KP_3 {81 86} KP_3 {81 87} KP_3 {81 88} Ascii_3 {81 89} Hex_3 {81 90} KP_3 {81 91} KP_3 {81 92} KP_3 {81 93} KP_3 {81 94} KP_3 {81 95} KP_3 {81 96} KP_3 {81 97} KP_3 {81 98} Hex_3 {81 99} KP_3 {81 100} KP_3 {81 101} KP_3 {81 102} KP_3 {81 103} KP_3 {81 104} Ascii_3 {81 105} Hex_3 {81 106} KP_3 {81 107} KP_3 {81 108} KP_3 {81 109} KP_3 {81 110} KP_3 {81 111} KP_3 {81 112} KP_3 {81 113} KP_3 {81 114} Hex_3 {81 115} KP_3 {81 116} KP_3 {81 117} KP_3 {81 118} KP_3 {81 119} KP_3 {81 120} Ascii_3 {81 121} Hex_3 {81 122} KP_3 {81 123} KP_3 {81 124} KP_3 {81 125} KP_3 {81 126} KP_3 {81 127} KP_3 {82 0} KP_0 {82 1} KP_0 {82 2} Hex_0 {82 3} KP_0 {82 4} KP_0 {82 5} KP_0 {82 6} KP_0 {82 7} KP_0 {82 8} Ascii_0 {82 9} Hex_0 {82 10} KP_0 {82 11} KP_0 {82 12} KP_0 {82 13} KP_0 {82 14} KP_0 {82 15} KP_0 {82 16} KP_0 {82 17} KP_0 {82 18} Hex_0 {82 19} KP_0 {82 20} KP_0 {82 21} KP_0 {82 22} KP_0 {82 23} KP_0 {82 24} Ascii_0 {82 25} Hex_0 {82 26} KP_0 {82 27} KP_0 {82 28} KP_0 {82 29} KP_0 {82 30} KP_0 {82 31} KP_0 {82 32} KP_0 {82 33} KP_0 {82 34} Hex_0 {82 35} KP_0 {82 36} KP_0 {82 37} KP_0 {82 38} KP_0 {82 39} KP_0 {82 40} Ascii_0 {82 41} Hex_0 {82 42} KP_0 {82 43} KP_0 {82 44} KP_0 {82 45} KP_0 {82 46} KP_0 {82 47} KP_0 {82 48} KP_0 {82 49} KP_0 {82 50} Hex_0 {82 51} KP_0 {82 52} KP_0 {82 53} KP_0 {82 54} KP_0 {82 55} KP_0 {82 56} Ascii_0 {82 57} Hex_0 {82 58} KP_0 {82 59} KP_0 {82 60} KP_0 {82 61} KP_0 {82 62} KP_0 {82 63} KP_0 {82 64} KP_0 {82 65} KP_0 {82 66} Hex_0 {82 67} KP_0 {82 68} KP_0 {82 69} KP_0 {82 70} KP_0 {82 71} KP_0 {82 72} Ascii_0 {82 73} Hex_0 {82 74} KP_0 {82 75} KP_0 {82 76} KP_0 {82 77} KP_0 {82 78} KP_0 {82 79} KP_0 {82 80} KP_0 {82 81} KP_0 {82 82} Hex_0 {82 83} KP_0 {82 84} KP_0 {82 85} KP_0 {82 86} KP_0 {82 87} KP_0 {82 88} Ascii_0 {82 89} Hex_0 {82 90} KP_0 {82 91} KP_0 {82 92} KP_0 {82 93} KP_0 {82 94} KP_0 {82 95} KP_0 {82 96} KP_0 {82 97} KP_0 {82 98} Hex_0 {82 99} KP_0 {82 100} KP_0 {82 101} KP_0 {82 102} KP_0 {82 103} KP_0 {82 104} Ascii_0 {82 105} Hex_0 {82 106} KP_0 {82 107} KP_0 {82 108} KP_0 {82 109} KP_0 {82 110} KP_0 {82 111} KP_0 {82 112} KP_0 {82 113} KP_0 {82 114} Hex_0 {82 115} KP_0 {82 116} KP_0 {82 117} KP_0 {82 118} KP_0 {82 119} KP_0 {82 120} Ascii_0 {82 121} Hex_0 {82 122} KP_0 {82 123} KP_0 {82 124} KP_0 {82 125} KP_0 {82 126} KP_0 {82 127} KP_0 {83 0} KP_Period {83 1} KP_Period {83 2} KP_Period {83 3} KP_Period {83 4} KP_Period {83 5} KP_Period {83 6} Boot {83 7} KP_Period {83 8} KP_Period {83 9} KP_Period {83 10} KP_Period {83 11} KP_Period {83 12} Boot {83 13} KP_Period {83 14} Boot {83 15} KP_Period {83 16} KP_Period {83 17} KP_Period {83 18} KP_Period {83 19} KP_Period {83 20} KP_Period {83 21} KP_Period {83 22} Boot {83 23} KP_Period {83 24} KP_Period {83 25} KP_Period {83 26} KP_Period {83 27} KP_Period {83 28} Boot {83 29} KP_Period {83 30} Boot {83 31} KP_Period {83 32} KP_Period {83 33} KP_Period {83 34} KP_Period {83 35} KP_Period {83 36} KP_Period {83 37} KP_Period {83 38} Boot {83 39} KP_Period {83 40} KP_Period {83 41} KP_Period {83 42} KP_Period {83 43} KP_Period {83 44} Boot {83 45} KP_Period {83 46} Boot {83 47} KP_Period {83 48} KP_Period {83 49} KP_Period {83 50} KP_Period {83 51} KP_Period {83 52} KP_Period {83 53} KP_Period {83 54} Boot {83 55} KP_Period {83 56} KP_Period {83 57} KP_Period {83 58} KP_Period {83 59} KP_Period {83 60} Boot {83 61} KP_Period {83 62} Boot {83 63} KP_Period {83 64} KP_Period {83 65} KP_Period {83 66} KP_Period {83 67} KP_Period {83 68} KP_Period {83 69} KP_Period {83 70} Boot {83 71} KP_Period {83 72} KP_Period {83 73} KP_Period {83 74} KP_Period {83 75} KP_Period {83 76} Boot {83 77} KP_Period {83 78} Boot {83 79} KP_Period {83 80} KP_Period {83 81} KP_Period {83 82} KP_Period {83 83} KP_Period {83 84} KP_Period {83 85} KP_Period {83 86} Boot {83 87} KP_Period {83 88} KP_Period {83 89} KP_Period {83 90} KP_Period {83 91} KP_Period {83 92} Boot {83 93} KP_Period {83 94} Boot {83 95} KP_Period {83 96} KP_Period {83 97} KP_Period {83 98} KP_Period {83 99} KP_Period {83 100} KP_Period {83 101} KP_Period {83 102} Boot {83 103} KP_Period {83 104} KP_Period {83 105} KP_Period {83 106} KP_Period {83 107} KP_Period {83 108} Boot {83 109} KP_Period {83 110} Boot {83 111} KP_Period {83 112} KP_Period {83 113} KP_Period {83 114} KP_Period {83 115} KP_Period {83 116} KP_Period {83 117} KP_Period {83 118} Boot {83 119} KP_Period {83 120} KP_Period {83 121} KP_Period {83 122} KP_Period {83 123} KP_Period {83 124} Boot {83 125} KP_Period {83 126} Boot {83 127} KP_Period {84 0} Last_Console {84 1} Last_Console {84 2} Last_Console {84 3} Last_Console {84 4} Last_Console {84 5} Last_Console {84 6} Last_Console {84 7} Last_Console {84 8} Last_Console {84 9} Last_Console {84 10} Last_Console {84 11} Last_Console {84 12} Last_Console {84 13} Last_Console {84 14} Last_Console {84 15} Last_Console {84 16} Last_Console {84 17} Last_Console {84 18} Last_Console {84 19} Last_Console {84 20} Last_Console {84 21} Last_Console {84 22} Last_Console {84 23} Last_Console {84 24} Last_Console {84 25} Last_Console {84 26} Last_Console {84 27} Last_Console {84 28} Last_Console {84 29} Last_Console {84 30} Last_Console {84 31} Last_Console {84 32} Last_Console {84 33} Last_Console {84 34} Last_Console {84 35} Last_Console {84 36} Last_Console {84 37} Last_Console {84 38} Last_Console {84 39} Last_Console {84 40} Last_Console {84 41} Last_Console {84 42} Last_Console {84 43} Last_Console {84 44} Last_Console {84 45} Last_Console {84 46} Last_Console {84 47} Last_Console {84 48} Last_Console {84 49} Last_Console {84 50} Last_Console {84 51} Last_Console {84 52} Last_Console {84 53} Last_Console {84 54} Last_Console {84 55} Last_Console {84 56} Last_Console {84 57} Last_Console {84 58} Last_Console {84 59} Last_Console {84 60} Last_Console {84 61} Last_Console {84 62} Last_Console {84 63} Last_Console {84 64} Last_Console {84 65} Last_Console {84 66} Last_Console {84 67} Last_Console {84 68} Last_Console {84 69} Last_Console {84 70} Last_Console {84 71} Last_Console {84 72} Last_Console {84 73} Last_Console {84 74} Last_Console {84 75} Last_Console {84 76} Last_Console {84 77} Last_Console {84 78} Last_Console {84 79} Last_Console {84 80} Last_Console {84 81} Last_Console {84 82} Last_Console {84 83} Last_Console {84 84} Last_Console {84 85} Last_Console {84 86} Last_Console {84 87} Last_Console {84 88} Last_Console {84 89} Last_Console {84 90} Last_Console {84 91} Last_Console {84 92} Last_Console {84 93} Last_Console {84 94} Last_Console {84 95} Last_Console {84 96} Last_Console {84 97} Last_Console {84 98} Last_Console {84 99} Last_Console {84 100} Last_Console {84 101} Last_Console {84 102} Last_Console {84 103} Last_Console {84 104} Last_Console {84 105} Last_Console {84 106} Last_Console {84 107} Last_Console {84 108} Last_Console {84 109} Last_Console {84 110} Last_Console {84 111} Last_Console {84 112} Last_Console {84 113} Last_Console {84 114} Last_Console {84 115} Last_Console {84 116} Last_Console {84 117} Last_Console {84 118} Last_Console {84 119} Last_Console {84 120} Last_Console {84 121} Last_Console {84 122} Last_Console {84 123} Last_Console {84 124} Last_Console {84 125} Last_Console {84 126} Last_Console {84 127} Last_Console {86 0} less {86 1} greater {86 2} bar {86 3} brokenbar {86 4} Control_backslash {86 5} greater {86 6} Control_backslash {86 7} Control_backslash {86 8} Meta_less {86 9} Meta_greater {86 10} Meta_bar {86 11} Meta_bar {86 12} Meta_Control_backslash {86 13} Meta_greater {86 14} Meta_Control_backslash {86 15} Meta_Control_backslash {86 16} less {86 17} greater {86 18} bar {86 19} brokenbar {86 20} Control_backslash {86 21} greater {86 22} Control_backslash {86 23} Control_backslash {86 24} Meta_less {86 25} Meta_greater {86 26} Meta_bar {86 27} Meta_bar {86 28} Meta_Control_backslash {86 29} Meta_greater {86 30} Meta_Control_backslash {86 31} Meta_Control_backslash {86 32} less {86 33} greater {86 34} bar {86 35} brokenbar {86 36} Control_backslash {86 37} greater {86 38} Control_backslash {86 39} Control_backslash {86 40} Meta_less {86 41} Meta_greater {86 42} Meta_bar {86 43} Meta_bar {86 44} Meta_Control_backslash {86 45} Meta_greater {86 46} Meta_Control_backslash {86 47} Meta_Control_backslash {86 48} less {86 49} greater {86 50} bar {86 51} brokenbar {86 52} Control_backslash {86 53} greater {86 54} Control_backslash {86 55} Control_backslash {86 56} Meta_less {86 57} Meta_greater {86 58} Meta_bar {86 59} Meta_bar {86 60} Meta_Control_backslash {86 61} Meta_greater {86 62} Meta_Control_backslash {86 63} Meta_Control_backslash {86 64} less {86 65} greater {86 66} bar {86 67} brokenbar {86 68} Control_backslash {86 69} greater {86 70} Control_backslash {86 71} Control_backslash {86 72} Meta_less {86 73} Meta_greater {86 74} Meta_bar {86 75} Meta_bar {86 76} Meta_Control_backslash {86 77} Meta_greater {86 78} Meta_Control_backslash {86 79} Meta_Control_backslash {86 80} less {86 81} greater {86 82} bar {86 83} brokenbar {86 84} Control_backslash {86 85} greater {86 86} Control_backslash {86 87} Control_backslash {86 88} Meta_less {86 89} Meta_greater {86 90} Meta_bar {86 91} Meta_bar {86 92} Meta_Control_backslash {86 93} Meta_greater {86 94} Meta_Control_backslash {86 95} Meta_Control_backslash {86 96} less {86 97} greater {86 98} bar {86 99} brokenbar {86 100} Control_backslash {86 101} greater {86 102} Control_backslash {86 103} Control_backslash {86 104} Meta_less {86 105} Meta_greater {86 106} Meta_bar {86 107} Meta_bar {86 108} Meta_Control_backslash {86 109} Meta_greater {86 110} Meta_Control_backslash {86 111} Meta_Control_backslash {86 112} less {86 113} greater {86 114} bar {86 115} brokenbar {86 116} Control_backslash {86 117} greater {86 118} Control_backslash {86 119} Control_backslash {86 120} Meta_less {86 121} Meta_greater {86 122} Meta_bar {86 123} Meta_bar {86 124} Meta_Control_backslash {86 125} Meta_greater {86 126} Meta_Control_backslash {86 127} Meta_Control_backslash {87 0} F11 {87 1} F23 {87 2} Console_23 {87 3} Console_35 {87 4} F35 {87 5} F47 {87 6} Console_23 {87 7} Console_35 {87 8} Console_11 {87 9} Console_23 {87 10} F11 {87 11} F11 {87 12} Console_11 {87 13} Console_23 {87 14} F11 {87 15} F11 {87 16} F11 {87 17} F23 {87 18} Console_23 {87 19} Console_35 {87 20} F35 {87 21} F47 {87 22} Console_23 {87 23} Console_35 {87 24} Console_11 {87 25} Console_23 {87 26} F11 {87 27} F11 {87 28} Console_11 {87 29} Console_23 {87 30} F11 {87 31} F11 {87 32} F11 {87 33} F23 {87 34} Console_23 {87 35} Console_35 {87 36} F35 {87 37} F47 {87 38} Console_23 {87 39} Console_35 {87 40} Console_11 {87 41} Console_23 {87 42} F11 {87 43} F11 {87 44} Console_11 {87 45} Console_23 {87 46} F11 {87 47} F11 {87 48} F11 {87 49} F23 {87 50} Console_23 {87 51} Console_35 {87 52} F35 {87 53} F47 {87 54} Console_23 {87 55} Console_35 {87 56} Console_11 {87 57} Console_23 {87 58} F11 {87 59} F11 {87 60} Console_11 {87 61} Console_23 {87 62} F11 {87 63} F11 {87 64} F11 {87 65} F23 {87 66} Console_23 {87 67} Console_35 {87 68} F35 {87 69} F47 {87 70} Console_23 {87 71} Console_35 {87 72} Console_11 {87 73} Console_23 {87 74} F11 {87 75} F11 {87 76} Console_11 {87 77} Console_23 {87 78} F11 {87 79} F11 {87 80} F11 {87 81} F23 {87 82} Console_23 {87 83} Console_35 {87 84} F35 {87 85} F47 {87 86} Console_23 {87 87} Console_35 {87 88} Console_11 {87 89} Console_23 {87 90} F11 {87 91} F11 {87 92} Console_11 {87 93} Console_23 {87 94} F11 {87 95} F11 {87 96} F11 {87 97} F23 {87 98} Console_23 {87 99} Console_35 {87 100} F35 {87 101} F47 {87 102} Console_23 {87 103} Console_35 {87 104} Console_11 {87 105} Console_23 {87 106} F11 {87 107} F11 {87 108} Console_11 {87 109} Console_23 {87 110} F11 {87 111} F11 {87 112} F11 {87 113} F23 {87 114} Console_23 {87 115} Console_35 {87 116} F35 {87 117} F47 {87 118} Console_23 {87 119} Console_35 {87 120} Console_11 {87 121} Console_23 {87 122} F11 {87 123} F11 {87 124} Console_11 {87 125} Console_23 {87 126} F11 {87 127} F11 {88 0} F12 {88 1} F24 {88 2} Console_24 {88 3} Console_36 {88 4} F36 {88 5} F48 {88 6} Console_24 {88 7} Console_36 {88 8} Console_12 {88 9} Console_24 {88 10} F12 {88 11} F12 {88 12} Console_12 {88 13} Console_24 {88 14} F12 {88 15} F12 {88 16} F12 {88 17} F24 {88 18} Console_24 {88 19} Console_36 {88 20} F36 {88 21} F48 {88 22} Console_24 {88 23} Console_36 {88 24} Console_12 {88 25} Console_24 {88 26} F12 {88 27} F12 {88 28} Console_12 {88 29} Console_24 {88 30} F12 {88 31} F12 {88 32} F12 {88 33} F24 {88 34} Console_24 {88 35} Console_36 {88 36} F36 {88 37} F48 {88 38} Console_24 {88 39} Console_36 {88 40} Console_12 {88 41} Console_24 {88 42} F12 {88 43} F12 {88 44} Console_12 {88 45} Console_24 {88 46} F12 {88 47} F12 {88 48} F12 {88 49} F24 {88 50} Console_24 {88 51} Console_36 {88 52} F36 {88 53} F48 {88 54} Console_24 {88 55} Console_36 {88 56} Console_12 {88 57} Console_24 {88 58} F12 {88 59} F12 {88 60} Console_12 {88 61} Console_24 {88 62} F12 {88 63} F12 {88 64} F12 {88 65} F24 {88 66} Console_24 {88 67} Console_36 {88 68} F36 {88 69} F48 {88 70} Console_24 {88 71} Console_36 {88 72} Console_12 {88 73} Console_24 {88 74} F12 {88 75} F12 {88 76} Console_12 {88 77} Console_24 {88 78} F12 {88 79} F12 {88 80} F12 {88 81} F24 {88 82} Console_24 {88 83} Console_36 {88 84} F36 {88 85} F48 {88 86} Console_24 {88 87} Console_36 {88 88} Console_12 {88 89} Console_24 {88 90} F12 {88 91} F12 {88 92} Console_12 {88 93} Console_24 {88 94} F12 {88 95} F12 {88 96} F12 {88 97} F24 {88 98} Console_24 {88 99} Console_36 {88 100} F36 {88 101} F48 {88 102} Console_24 {88 103} Console_36 {88 104} Console_12 {88 105} Console_24 {88 106} F12 {88 107} F12 {88 108} Console_12 {88 109} Console_24 {88 110} F12 {88 111} F12 {88 112} F12 {88 113} F24 {88 114} Console_24 {88 115} Console_36 {88 116} F36 {88 117} F48 {88 118} Console_24 {88 119} Console_36 {88 120} Console_12 {88 121} Console_24 {88 122} F12 {88 123} F12 {88 124} Console_12 {88 125} Console_24 {88 126} F12 {88 127} F12 {96 0} KP_Enter {96 1} KP_Enter {96 2} Hex_F {96 3} KP_Enter {96 4} KP_Enter {96 5} KP_Enter {96 6} KP_Enter {96 7} KP_Enter {96 8} KP_Enter {96 9} Hex_F {96 10} KP_Enter {96 11} KP_Enter {96 12} KP_Enter {96 13} KP_Enter {96 14} KP_Enter {96 15} KP_Enter {96 16} KP_Enter {96 17} KP_Enter {96 18} Hex_F {96 19} KP_Enter {96 20} KP_Enter {96 21} KP_Enter {96 22} KP_Enter {96 23} KP_Enter {96 24} KP_Enter {96 25} Hex_F {96 26} KP_Enter {96 27} KP_Enter {96 28} KP_Enter {96 29} KP_Enter {96 30} KP_Enter {96 31} KP_Enter {96 32} KP_Enter {96 33} KP_Enter {96 34} Hex_F {96 35} KP_Enter {96 36} KP_Enter {96 37} KP_Enter {96 38} KP_Enter {96 39} KP_Enter {96 40} KP_Enter {96 41} Hex_F {96 42} KP_Enter {96 43} KP_Enter {96 44} KP_Enter {96 45} KP_Enter {96 46} KP_Enter {96 47} KP_Enter {96 48} KP_Enter {96 49} KP_Enter {96 50} Hex_F {96 51} KP_Enter {96 52} KP_Enter {96 53} KP_Enter {96 54} KP_Enter {96 55} KP_Enter {96 56} KP_Enter {96 57} Hex_F {96 58} KP_Enter {96 59} KP_Enter {96 60} KP_Enter {96 61} KP_Enter {96 62} KP_Enter {96 63} KP_Enter {96 64} KP_Enter {96 65} KP_Enter {96 66} Hex_F {96 67} KP_Enter {96 68} KP_Enter {96 69} KP_Enter {96 70} KP_Enter {96 71} KP_Enter {96 72} KP_Enter {96 73} Hex_F {96 74} KP_Enter {96 75} KP_Enter {96 76} KP_Enter {96 77} KP_Enter {96 78} KP_Enter {96 79} KP_Enter {96 80} KP_Enter {96 81} KP_Enter {96 82} Hex_F {96 83} KP_Enter {96 84} KP_Enter {96 85} KP_Enter {96 86} KP_Enter {96 87} KP_Enter {96 88} KP_Enter {96 89} Hex_F {96 90} KP_Enter {96 91} KP_Enter {96 92} KP_Enter {96 93} KP_Enter {96 94} KP_Enter {96 95} KP_Enter {96 96} KP_Enter {96 97} KP_Enter {96 98} Hex_F {96 99} KP_Enter {96 100} KP_Enter {96 101} KP_Enter {96 102} KP_Enter {96 103} KP_Enter {96 104} KP_Enter {96 105} Hex_F {96 106} KP_Enter {96 107} KP_Enter {96 108} KP_Enter {96 109} KP_Enter {96 110} KP_Enter {96 111} KP_Enter {96 112} KP_Enter {96 113} KP_Enter {96 114} Hex_F {96 115} KP_Enter {96 116} KP_Enter {96 117} KP_Enter {96 118} KP_Enter {96 119} KP_Enter {96 120} KP_Enter {96 121} Hex_F {96 122} KP_Enter {96 123} KP_Enter {96 124} KP_Enter {96 125} KP_Enter {96 126} KP_Enter {96 127} KP_Enter {97 0} Control {97 1} Control {97 2} Control {97 3} Control {97 4} Control {97 5} Control {97 6} Control {97 7} Control {97 8} Control {97 9} Control {97 10} Control {97 11} Control {97 12} Control {97 13} Control {97 14} Control {97 15} Control {97 16} Control {97 17} Control {97 18} Control {97 19} Control {97 20} Control {97 21} Control {97 22} Control {97 23} Control {97 24} Control {97 25} Control {97 26} Control {97 27} Control {97 28} Control {97 29} Control {97 30} Control {97 31} Control {97 32} Control {97 33} Control {97 34} Control {97 35} Control {97 36} Control {97 37} Control {97 38} Control {97 39} Control {97 40} Control {97 41} Control {97 42} Control {97 43} Control {97 44} Control {97 45} Control {97 46} Control {97 47} Control {97 48} Control {97 49} Control {97 50} Control {97 51} Control {97 52} Control {97 53} Control {97 54} Control {97 55} Control {97 56} Control {97 57} Control {97 58} Control {97 59} Control {97 60} Control {97 61} Control {97 62} Control {97 63} Control {97 64} Control {97 65} Control {97 66} Control {97 67} Control {97 68} Control {97 69} Control {97 70} Control {97 71} Control {97 72} Control {97 73} Control {97 74} Control {97 75} Control {97 76} Control {97 77} Control {97 78} Control {97 79} Control {97 80} Control {97 81} Control {97 82} Control {97 83} Control {97 84} Control {97 85} Control {97 86} Control {97 87} Control {97 88} Control {97 89} Control {97 90} Control {97 91} Control {97 92} Control {97 93} Control {97 94} Control {97 95} Control {97 96} Control {97 97} Control {97 98} Control {97 99} Control {97 100} Control {97 101} Control {97 102} Control {97 103} Control {97 104} Control {97 105} Control {97 106} Control {97 107} Control {97 108} Control {97 109} Control {97 110} Control {97 111} Control {97 112} Control {97 113} Control {97 114} Control {97 115} Control {97 116} Control {97 117} Control {97 118} Control {97 119} Control {97 120} Control {97 121} Control {97 122} Control {97 123} Control {97 124} Control {97 125} Control {97 126} Control {97 127} Control {98 0} KP_Divide {98 1} KP_Divide {98 2} Hex_B {98 3} KP_Divide {98 4} KP_Divide {98 5} KP_Divide {98 6} KP_Divide {98 7} KP_Divide {98 8} KP_Divide {98 9} Hex_B {98 10} KP_Divide {98 11} KP_Divide {98 12} KP_Divide {98 13} KP_Divide {98 14} KP_Divide {98 15} KP_Divide {98 16} KP_Divide {98 17} KP_Divide {98 18} Hex_B {98 19} KP_Divide {98 20} KP_Divide {98 21} KP_Divide {98 22} KP_Divide {98 23} KP_Divide {98 24} KP_Divide {98 25} Hex_B {98 26} KP_Divide {98 27} KP_Divide {98 28} KP_Divide {98 29} KP_Divide {98 30} KP_Divide {98 31} KP_Divide {98 32} KP_Divide {98 33} KP_Divide {98 34} Hex_B {98 35} KP_Divide {98 36} KP_Divide {98 37} KP_Divide {98 38} KP_Divide {98 39} KP_Divide {98 40} KP_Divide {98 41} Hex_B {98 42} KP_Divide {98 43} KP_Divide {98 44} KP_Divide {98 45} KP_Divide {98 46} KP_Divide {98 47} KP_Divide {98 48} KP_Divide {98 49} KP_Divide {98 50} Hex_B {98 51} KP_Divide {98 52} KP_Divide {98 53} KP_Divide {98 54} KP_Divide {98 55} KP_Divide {98 56} KP_Divide {98 57} Hex_B {98 58} KP_Divide {98 59} KP_Divide {98 60} KP_Divide {98 61} KP_Divide {98 62} KP_Divide {98 63} KP_Divide {98 64} KP_Divide {98 65} KP_Divide {98 66} Hex_B {98 67} KP_Divide {98 68} KP_Divide {98 69} KP_Divide {98 70} KP_Divide {98 71} KP_Divide {98 72} KP_Divide {98 73} Hex_B {98 74} KP_Divide {98 75} KP_Divide {98 76} KP_Divide {98 77} KP_Divide {98 78} KP_Divide {98 79} KP_Divide {98 80} KP_Divide {98 81} KP_Divide {98 82} Hex_B {98 83} KP_Divide {98 84} KP_Divide {98 85} KP_Divide {98 86} KP_Divide {98 87} KP_Divide {98 88} KP_Divide {98 89} Hex_B {98 90} KP_Divide {98 91} KP_Divide {98 92} KP_Divide {98 93} KP_Divide {98 94} KP_Divide {98 95} KP_Divide {98 96} KP_Divide {98 97} KP_Divide {98 98} Hex_B {98 99} KP_Divide {98 100} KP_Divide {98 101} KP_Divide {98 102} KP_Divide {98 103} KP_Divide {98 104} KP_Divide {98 105} Hex_B {98 106} KP_Divide {98 107} KP_Divide {98 108} KP_Divide {98 109} KP_Divide {98 110} KP_Divide {98 111} KP_Divide {98 112} KP_Divide {98 113} KP_Divide {98 114} Hex_B {98 115} KP_Divide {98 116} KP_Divide {98 117} KP_Divide {98 118} KP_Divide {98 119} KP_Divide {98 120} KP_Divide {98 121} Hex_B {98 122} KP_Divide {98 123} KP_Divide {98 124} KP_Divide {98 125} KP_Divide {98 126} KP_Divide {98 127} KP_Divide {99 0} Control_backslash {99 1} Control_backslash {99 2} Control_backslash {99 3} Control_backslash {99 4} Control_backslash {99 5} Control_backslash {99 6} Last_Console {99 7} Last_Console {99 8} Last_Console {99 9} Last_Console {99 10} Meta_Control_backslash {99 11} Meta_Control_backslash {99 12} Meta_Control_backslash {99 13} Meta_Control_backslash {99 14} Control_backslash {99 15} Control_backslash {99 16} Control_backslash {99 17} Control_backslash {99 18} Control_backslash {99 19} Control_backslash {99 20} Last_Console {99 21} Last_Console {99 22} Last_Console {99 23} Last_Console {99 24} Meta_Control_backslash {99 25} Meta_Control_backslash {99 26} Meta_Control_backslash {99 27} Meta_Control_backslash {99 28} Control_backslash {99 29} Control_backslash {99 30} Control_backslash {99 31} Control_backslash {99 32} Control_backslash {99 33} Control_backslash {99 34} Last_Console {99 35} Last_Console {99 36} Last_Console {99 37} Last_Console {99 38} Meta_Control_backslash {99 39} Meta_Control_backslash {99 40} Meta_Control_backslash {99 41} Meta_Control_backslash {99 42} Control_backslash {99 43} Control_backslash {99 44} Control_backslash {99 45} Control_backslash {99 46} Control_backslash {99 47} Control_backslash {99 48} Last_Console {99 49} Last_Console {99 50} Last_Console {99 51} Last_Console {99 52} Meta_Control_backslash {99 53} Meta_Control_backslash {99 54} Meta_Control_backslash {99 55} Meta_Control_backslash {99 56} Control_backslash {99 57} Control_backslash {99 58} Control_backslash {99 59} Control_backslash {99 60} Control_backslash {99 61} Control_backslash {99 62} Last_Console {99 63} Last_Console {99 64} Last_Console {99 65} Last_Console {99 66} Meta_Control_backslash {99 67} Meta_Control_backslash {99 68} Meta_Control_backslash {99 69} Meta_Control_backslash {99 70} Control_backslash {99 71} Control_backslash {99 72} Control_backslash {99 73} Control_backslash {99 74} Control_backslash {99 75} Control_backslash {99 76} Last_Console {99 77} Last_Console {99 78} Last_Console {99 79} Last_Console {99 80} Meta_Control_backslash {99 81} Meta_Control_backslash {99 82} Meta_Control_backslash {99 83} Meta_Control_backslash {99 84} Control_backslash {99 85} Control_backslash {99 86} Control_backslash {99 87} Control_backslash {99 88} Control_backslash {99 89} Control_backslash {99 90} Last_Console {99 91} Last_Console {99 92} Last_Console {99 93} Last_Console {99 94} Meta_Control_backslash {99 95} Meta_Control_backslash {99 96} Meta_Control_backslash {99 97} Meta_Control_backslash {99 98} Control_backslash {99 99} Control_backslash {99 100} Control_backslash {99 101} Control_backslash {99 102} Control_backslash {99 103} Control_backslash {99 104} Last_Console {99 105} Last_Console {99 106} Last_Console {99 107} Last_Console {99 108} Meta_Control_backslash {99 109} Meta_Control_backslash {99 110} Meta_Control_backslash {99 111} Meta_Control_backslash {100 0} Alt {100 1} Alt {100 2} Alt {100 3} Alt {100 4} Alt {100 5} Alt {100 6} Alt {100 7} Alt {100 8} Alt {100 9} Alt {100 10} Alt {100 11} Alt {100 12} Alt {100 13} Alt {100 14} Alt {100 15} Alt {100 16} Alt {100 17} Alt {100 18} Alt {100 19} Alt {100 20} Alt {100 21} Alt {100 22} Alt {100 23} Alt {100 24} Alt {100 25} Alt {100 26} Alt {100 27} Alt {100 28} Alt {100 29} Alt {100 30} Alt {100 31} Alt {100 32} Alt {100 33} Alt {100 34} Alt {100 35} Alt {100 36} Alt {100 37} Alt {100 38} Alt {100 39} Alt {100 40} Alt {100 41} Alt {100 42} Alt {100 43} Alt {100 44} Alt {100 45} Alt {100 46} Alt {100 47} Alt {100 48} Alt {100 49} Alt {100 50} Alt {100 51} Alt {100 52} Alt {100 53} Alt {100 54} Alt {100 55} Alt {100 56} Alt {100 57} Alt {100 58} Alt {100 59} Alt {100 60} Alt {100 61} Alt {100 62} Alt {100 63} Alt {100 64} Alt {100 65} Alt {100 66} Alt {100 67} Alt {100 68} Alt {100 69} Alt {100 70} Alt {100 71} Alt {100 72} Alt {100 73} Alt {100 74} Alt {100 75} Alt {100 76} Alt {100 77} Alt {100 78} Alt {100 79} Alt {100 80} Alt {100 81} Alt {100 82} Alt {100 83} Alt {100 84} Alt {100 85} Alt {100 86} Alt {100 87} Alt {100 88} Alt {100 89} Alt {100 90} Alt {100 91} Alt {100 92} Alt {100 93} Alt {100 94} Alt {100 95} Alt {100 96} Alt {100 97} Alt {100 98} Alt {100 99} Alt {100 100} Alt {100 101} Alt {100 102} Alt {100 103} Alt {100 104} Alt {100 105} Alt {100 106} Alt {100 107} Alt {100 108} Alt {100 109} Alt {100 110} Alt {100 111} Alt {100 112} Alt {100 113} Alt {100 114} Alt {100 115} Alt {100 116} Alt {100 117} Alt {100 118} Alt {100 119} Alt {100 120} Alt {100 121} Alt {100 122} Alt {100 123} Alt {100 124} Alt {100 125} Alt {100 126} Alt {100 127} Alt {101 0} Break {101 1} Break {101 2} Break {101 3} Break {101 4} Break {101 5} Break {101 6} Break {101 7} Break {101 8} Break {101 9} Break {101 10} Break {101 11} Break {101 12} Break {101 13} Break {101 14} Break {101 15} Break {101 16} Break {101 17} Break {101 18} Break {101 19} Break {101 20} Break {101 21} Break {101 22} Break {101 23} Break {101 24} Break {101 25} Break {101 26} Break {101 27} Break {101 28} Break {101 29} Break {101 30} Break {101 31} Break {101 32} Break {101 33} Break {101 34} Break {101 35} Break {101 36} Break {101 37} Break {101 38} Break {101 39} Break {101 40} Break {101 41} Break {101 42} Break {101 43} Break {101 44} Break {101 45} Break {101 46} Break {101 47} Break {101 48} Break {101 49} Break {101 50} Break {101 51} Break {101 52} Break {101 53} Break {101 54} Break {101 55} Break {101 56} Break {101 57} Break {101 58} Break {101 59} Break {101 60} Break {101 61} Break {101 62} Break {101 63} Break {101 64} Break {101 65} Break {101 66} Break {101 67} Break {101 68} Break {101 69} Break {101 70} Break {101 71} Break {101 72} Break {101 73} Break {101 74} Break {101 75} Break {101 76} Break {101 77} Break {101 78} Break {101 79} Break {101 80} Break {101 81} Break {101 82} Break {101 83} Break {101 84} Break {101 85} Break {101 86} Break {101 87} Break {101 88} Break {101 89} Break {101 90} Break {101 91} Break {101 92} Break {101 93} Break {101 94} Break {101 95} Break {101 96} Break {101 97} Break {101 98} Break {101 99} Break {101 100} Break {101 101} Break {101 102} Break {101 103} Break {101 104} Break {101 105} Break {101 106} Break {101 107} Break {101 108} Break {101 109} Break {101 110} Break {101 111} Break {101 112} Break {101 113} Break {101 114} Break {101 115} Break {101 116} Break {101 117} Break {101 118} Break {101 119} Break {101 120} Break {101 121} Break {101 122} Break {101 123} Break {101 124} Break {101 125} Break {101 126} Break {101 127} Break {102 0} Find {102 1} Find {102 2} Find {102 3} Find {102 4} Find {102 5} Find {102 6} Find {102 7} Find {102 8} Find {102 9} Find {102 10} Find {102 11} Find {102 12} Find {102 13} Find {102 14} Find {102 15} Find {102 16} Find {102 17} Find {102 18} Find {102 19} Find {102 20} Find {102 21} Find {102 22} Find {102 23} Find {102 24} Find {102 25} Find {102 26} Find {102 27} Find {102 28} Find {102 29} Find {102 30} Find {102 31} Find {102 32} Find {102 33} Find {102 34} Find {102 35} Find {102 36} Find {102 37} Find {102 38} Find {102 39} Find {102 40} Find {102 41} Find {102 42} Find {102 43} Find {102 44} Find {102 45} Find {102 46} Find {102 47} Find {102 48} Find {102 49} Find {102 50} Find {102 51} Find {102 52} Find {102 53} Find {102 54} Find {102 55} Find {102 56} Find {102 57} Find {102 58} Find {102 59} Find {102 60} Find {102 61} Find {102 62} Find {102 63} Find {102 64} Find {102 65} Find {102 66} Find {102 67} Find {102 68} Find {102 69} Find {102 70} Find {102 71} Find {102 72} Find {102 73} Find {102 74} Find {102 75} Find {102 76} Find {102 77} Find {102 78} Find {102 79} Find {102 80} Find {102 81} Find {102 82} Find {102 83} Find {102 84} Find {102 85} Find {102 86} Find {102 87} Find {102 88} Find {102 89} Find {102 90} Find {102 91} Find {102 92} Find {102 93} Find {102 94} Find {102 95} Find {102 96} Find {102 97} Find {102 98} Find {102 99} Find {102 100} Find {102 101} Find {102 102} Find {102 103} Find {102 104} Find {102 105} Find {102 106} Find {102 107} Find {102 108} Find {102 109} Find {102 110} Find {102 111} Find {102 112} Find {102 113} Find {102 114} Find {102 115} Find {102 116} Find {102 117} Find {102 118} Find {102 119} Find {102 120} Find {102 121} Find {102 122} Find {102 123} Find {102 124} Find {102 125} Find {102 126} Find {102 127} Find {103 0} Up {103 1} Up {103 2} Up {103 3} Up {103 4} Up {103 5} Up {103 6} Up {103 7} Up {103 8} KeyboardSignal {103 9} Up {103 10} Up {103 11} Up {103 12} Up {103 13} Up {103 14} Up {103 15} Up {103 16} Up {103 17} Up {103 18} Up {103 19} Up {103 20} Up {103 21} Up {103 22} Up {103 23} Up {103 24} KeyboardSignal {103 25} Up {103 26} Up {103 27} Up {103 28} Up {103 29} Up {103 30} Up {103 31} Up {103 32} Up {103 33} Up {103 34} Up {103 35} Up {103 36} Up {103 37} Up {103 38} Up {103 39} Up {103 40} KeyboardSignal {103 41} Up {103 42} Up {103 43} Up {103 44} Up {103 45} Up {103 46} Up {103 47} Up {103 48} Up {103 49} Up {103 50} Up {103 51} Up {103 52} Up {103 53} Up {103 54} Up {103 55} Up {103 56} KeyboardSignal {103 57} Up {103 58} Up {103 59} Up {103 60} Up {103 61} Up {103 62} Up {103 63} Up {103 64} Up {103 65} Up {103 66} Up {103 67} Up {103 68} Up {103 69} Up {103 70} Up {103 71} Up {103 72} KeyboardSignal {103 73} Up {103 74} Up {103 75} Up {103 76} Up {103 77} Up {103 78} Up {103 79} Up {103 80} Up {103 81} Up {103 82} Up {103 83} Up {103 84} Up {103 85} Up {103 86} Up {103 87} Up {103 88} KeyboardSignal {103 89} Up {103 90} Up {103 91} Up {103 92} Up {103 93} Up {103 94} Up {103 95} Up {103 96} Up {103 97} Up {103 98} Up {103 99} Up {103 100} Up {103 101} Up {103 102} Up {103 103} Up {103 104} KeyboardSignal {103 105} Up {103 106} Up {103 107} Up {103 108} Up {103 109} Up {103 110} Up {103 111} Up {103 112} Up {103 113} Up {103 114} Up {103 115} Up {103 116} Up {103 117} Up {103 118} Up {103 119} Up {103 120} KeyboardSignal {103 121} Up {103 122} Up {103 123} Up {103 124} Up {103 125} Up {103 126} Up {103 127} Up {104 0} Prior {104 1} Scroll_Backward {104 2} Prior {104 3} Prior {104 4} Prior {104 5} Prior {104 6} Prior {104 7} Prior {104 8} Prior {104 9} Prior {104 10} Prior {104 11} Prior {104 12} Prior {104 13} Prior {104 14} Prior {104 15} Prior {104 16} Prior {104 17} Scroll_Backward {104 18} Prior {104 19} Prior {104 20} Prior {104 21} Prior {104 22} Prior {104 23} Prior {104 24} Prior {104 25} Prior {104 26} Prior {104 27} Prior {104 28} Prior {104 29} Prior {104 30} Prior {104 31} Prior {104 32} Prior {104 33} Scroll_Backward {104 34} Prior {104 35} Prior {104 36} Prior {104 37} Prior {104 38} Prior {104 39} Prior {104 40} Prior {104 41} Prior {104 42} Prior {104 43} Prior {104 44} Prior {104 45} Prior {104 46} Prior {104 47} Prior {104 48} Prior {104 49} Scroll_Backward {104 50} Prior {104 51} Prior {104 52} Prior {104 53} Prior {104 54} Prior {104 55} Prior {104 56} Prior {104 57} Prior {104 58} Prior {104 59} Prior {104 60} Prior {104 61} Prior {104 62} Prior {104 63} Prior {104 64} Prior {104 65} Scroll_Backward {104 66} Prior {104 67} Prior {104 68} Prior {104 69} Prior {104 70} Prior {104 71} Prior {104 72} Prior {104 73} Prior {104 74} Prior {104 75} Prior {104 76} Prior {104 77} Prior {104 78} Prior {104 79} Prior {104 80} Prior {104 81} Scroll_Backward {104 82} Prior {104 83} Prior {104 84} Prior {104 85} Prior {104 86} Prior {104 87} Prior {104 88} Prior {104 89} Prior {104 90} Prior {104 91} Prior {104 92} Prior {104 93} Prior {104 94} Prior {104 95} Prior {104 96} Prior {104 97} Scroll_Backward {104 98} Prior {104 99} Prior {104 100} Prior {104 101} Prior {104 102} Prior {104 103} Prior {104 104} Prior {104 105} Prior {104 106} Prior {104 107} Prior {104 108} Prior {104 109} Prior {104 110} Prior {104 111} Prior {104 112} Prior {104 113} Scroll_Backward {104 114} Prior {104 115} Prior {104 116} Prior {104 117} Prior {104 118} Prior {104 119} Prior {104 120} Prior {104 121} Prior {104 122} Prior {104 123} Prior {104 124} Prior {104 125} Prior {104 126} Prior {104 127} Prior {105 0} Left {105 1} Left {105 2} Left {105 3} Left {105 4} Left {105 5} Left {105 6} Left {105 7} Left {105 8} Decr_Console {105 9} Left {105 10} Left {105 11} Left {105 12} Left {105 13} Left {105 14} Left {105 15} Left {105 16} Left {105 17} Left {105 18} Left {105 19} Left {105 20} Left {105 21} Left {105 22} Left {105 23} Left {105 24} Decr_Console {105 25} Left {105 26} Left {105 27} Left {105 28} Left {105 29} Left {105 30} Left {105 31} Left {105 32} Left {105 33} Left {105 34} Left {105 35} Left {105 36} Left {105 37} Left {105 38} Left {105 39} Left {105 40} Decr_Console {105 41} Left {105 42} Left {105 43} Left {105 44} Left {105 45} Left {105 46} Left {105 47} Left {105 48} Left {105 49} Left {105 50} Left {105 51} Left {105 52} Left {105 53} Left {105 54} Left {105 55} Left {105 56} Decr_Console {105 57} Left {105 58} Left {105 59} Left {105 60} Left {105 61} Left {105 62} Left {105 63} Left {105 64} Left {105 65} Left {105 66} Left {105 67} Left {105 68} Left {105 69} Left {105 70} Left {105 71} Left {105 72} Decr_Console {105 73} Left {105 74} Left {105 75} Left {105 76} Left {105 77} Left {105 78} Left {105 79} Left {105 80} Left {105 81} Left {105 82} Left {105 83} Left {105 84} Left {105 85} Left {105 86} Left {105 87} Left {105 88} Decr_Console {105 89} Left {105 90} Left {105 91} Left {105 92} Left {105 93} Left {105 94} Left {105 95} Left {105 96} Left {105 97} Left {105 98} Left {105 99} Left {105 100} Left {105 101} Left {105 102} Left {105 103} Left {105 104} Decr_Console {105 105} Left {105 106} Left {105 107} Left {105 108} Left {105 109} Left {105 110} Left {105 111} Left {105 112} Left {105 113} Left {105 114} Left {105 115} Left {105 116} Left {105 117} Left {105 118} Left {105 119} Left {105 120} Decr_Console {105 121} Left {105 122} Left {105 123} Left {105 124} Left {105 125} Left {105 126} Left {105 127} Left {106 0} Right {106 1} Right {106 2} Right {106 3} Right {106 4} Right {106 5} Right {106 6} Right {106 7} Right {106 8} Incr_Console {106 9} Right {106 10} Right {106 11} Right {106 12} Right {106 13} Right {106 14} Right {106 15} Right {106 16} Right {106 17} Right {106 18} Right {106 19} Right {106 20} Right {106 21} Right {106 22} Right {106 23} Right {106 24} Incr_Console {106 25} Right {106 26} Right {106 27} Right {106 28} Right {106 29} Right {106 30} Right {106 31} Right {106 32} Right {106 33} Right {106 34} Right {106 35} Right {106 36} Right {106 37} Right {106 38} Right {106 39} Right {106 40} Incr_Console {106 41} Right {106 42} Right {106 43} Right {106 44} Right {106 45} Right {106 46} Right {106 47} Right {106 48} Right {106 49} Right {106 50} Right {106 51} Right {106 52} Right {106 53} Right {106 54} Right {106 55} Right {106 56} Incr_Console {106 57} Right {106 58} Right {106 59} Right {106 60} Right {106 61} Right {106 62} Right {106 63} Right {106 64} Right {106 65} Right {106 66} Right {106 67} Right {106 68} Right {106 69} Right {106 70} Right {106 71} Right {106 72} Incr_Console {106 73} Right {106 74} Right {106 75} Right {106 76} Right {106 77} Right {106 78} Right {106 79} Right {106 80} Right {106 81} Right {106 82} Right {106 83} Right {106 84} Right {106 85} Right {106 86} Right {106 87} Right {106 88} Incr_Console {106 89} Right {106 90} Right {106 91} Right {106 92} Right {106 93} Right {106 94} Right {106 95} Right {106 96} Right {106 97} Right {106 98} Right {106 99} Right {106 100} Right {106 101} Right {106 102} Right {106 103} Right {106 104} Incr_Console {106 105} Right {106 106} Right {106 107} Right {106 108} Right {106 109} Right {106 110} Right {106 111} Right {106 112} Right {106 113} Right {106 114} Right {106 115} Right {106 116} Right {106 117} Right {106 118} Right {106 119} Right {106 120} Incr_Console {106 121} Right {106 122} Right {106 123} Right {106 124} Right {106 125} Right {106 126} Right {106 127} Right {107 0} Select {107 1} Select {107 2} Select {107 3} Select {107 4} Select {107 5} Select {107 6} Select {107 7} Select {107 8} Select {107 9} Select {107 10} Select {107 11} Select {107 12} Select {107 13} Select {107 14} Select {107 15} Select {107 16} Select {107 17} Select {107 18} Select {107 19} Select {107 20} Select {107 21} Select {107 22} Select {107 23} Select {107 24} Select {107 25} Select {107 26} Select {107 27} Select {107 28} Select {107 29} Select {107 30} Select {107 31} Select {107 32} Select {107 33} Select {107 34} Select {107 35} Select {107 36} Select {107 37} Select {107 38} Select {107 39} Select {107 40} Select {107 41} Select {107 42} Select {107 43} Select {107 44} Select {107 45} Select {107 46} Select {107 47} Select {107 48} Select {107 49} Select {107 50} Select {107 51} Select {107 52} Select {107 53} Select {107 54} Select {107 55} Select {107 56} Select {107 57} Select {107 58} Select {107 59} Select {107 60} Select {107 61} Select {107 62} Select {107 63} Select {107 64} Select {107 65} Select {107 66} Select {107 67} Select {107 68} Select {107 69} Select {107 70} Select {107 71} Select {107 72} Select {107 73} Select {107 74} Select {107 75} Select {107 76} Select {107 77} Select {107 78} Select {107 79} Select {107 80} Select {107 81} Select {107 82} Select {107 83} Select {107 84} Select {107 85} Select {107 86} Select {107 87} Select {107 88} Select {107 89} Select {107 90} Select {107 91} Select {107 92} Select {107 93} Select {107 94} Select {107 95} Select {107 96} Select {107 97} Select {107 98} Select {107 99} Select {107 100} Select {107 101} Select {107 102} Select {107 103} Select {107 104} Select {107 105} Select {107 106} Select {107 107} Select {107 108} Select {107 109} Select {107 110} Select {107 111} Select {107 112} Select {107 113} Select {107 114} Select {107 115} Select {107 116} Select {107 117} Select {107 118} Select {107 119} Select {107 120} Select {107 121} Select {107 122} Select {107 123} Select {107 124} Select {107 125} Select {107 126} Select {107 127} Select {108 0} Down {108 1} Down {108 2} Down {108 3} Down {108 4} Down {108 5} Down {108 6} Down {108 7} Down {108 8} Down {108 9} Down {108 10} Down {108 11} Down {108 12} Down {108 13} Down {108 14} Down {108 15} Down {108 16} Down {108 17} Down {108 18} Down {108 19} Down {108 20} Down {108 21} Down {108 22} Down {108 23} Down {108 24} Down {108 25} Down {108 26} Down {108 27} Down {108 28} Down {108 29} Down {108 30} Down {108 31} Down {108 32} Down {108 33} Down {108 34} Down {108 35} Down {108 36} Down {108 37} Down {108 38} Down {108 39} Down {108 40} Down {108 41} Down {108 42} Down {108 43} Down {108 44} Down {108 45} Down {108 46} Down {108 47} Down {108 48} Down {108 49} Down {108 50} Down {108 51} Down {108 52} Down {108 53} Down {108 54} Down {108 55} Down {108 56} Down {108 57} Down {108 58} Down {108 59} Down {108 60} Down {108 61} Down {108 62} Down {108 63} Down {108 64} Down {108 65} Down {108 66} Down {108 67} Down {108 68} Down {108 69} Down {108 70} Down {108 71} Down {108 72} Down {108 73} Down {108 74} Down {108 75} Down {108 76} Down {108 77} Down {108 78} Down {108 79} Down {108 80} Down {108 81} Down {108 82} Down {108 83} Down {108 84} Down {108 85} Down {108 86} Down {108 87} Down {108 88} Down {108 89} Down {108 90} Down {108 91} Down {108 92} Down {108 93} Down {108 94} Down {108 95} Down {108 96} Down {108 97} Down {108 98} Down {108 99} Down {108 100} Down {108 101} Down {108 102} Down {108 103} Down {108 104} Down {108 105} Down {108 106} Down {108 107} Down {108 108} Down {108 109} Down {108 110} Down {108 111} Down {108 112} Down {108 113} Down {108 114} Down {108 115} Down {108 116} Down {108 117} Down {108 118} Down {108 119} Down {108 120} Down {108 121} Down {108 122} Down {108 123} Down {108 124} Down {108 125} Down {108 126} Down {108 127} Down {109 0} Next {109 1} Scroll_Forward {109 2} Next {109 3} Next {109 4} Next {109 5} Next {109 6} Next {109 7} Next {109 8} Next {109 9} Next {109 10} Next {109 11} Next {109 12} Next {109 13} Next {109 14} Next {109 15} Next {109 16} Next {109 17} Scroll_Forward {109 18} Next {109 19} Next {109 20} Next {109 21} Next {109 22} Next {109 23} Next {109 24} Next {109 25} Next {109 26} Next {109 27} Next {109 28} Next {109 29} Next {109 30} Next {109 31} Next {109 32} Next {109 33} Scroll_Forward {109 34} Next {109 35} Next {109 36} Next {109 37} Next {109 38} Next {109 39} Next {109 40} Next {109 41} Next {109 42} Next {109 43} Next {109 44} Next {109 45} Next {109 46} Next {109 47} Next {109 48} Next {109 49} Scroll_Forward {109 50} Next {109 51} Next {109 52} Next {109 53} Next {109 54} Next {109 55} Next {109 56} Next {109 57} Next {109 58} Next {109 59} Next {109 60} Next {109 61} Next {109 62} Next {109 63} Next {109 64} Next {109 65} Scroll_Forward {109 66} Next {109 67} Next {109 68} Next {109 69} Next {109 70} Next {109 71} Next {109 72} Next {109 73} Next {109 74} Next {109 75} Next {109 76} Next {109 77} Next {109 78} Next {109 79} Next {109 80} Next {109 81} Scroll_Forward {109 82} Next {109 83} Next {109 84} Next {109 85} Next {109 86} Next {109 87} Next {109 88} Next {109 89} Next {109 90} Next {109 91} Next {109 92} Next {109 93} Next {109 94} Next {109 95} Next {109 96} Next {109 97} Scroll_Forward {109 98} Next {109 99} Next {109 100} Next {109 101} Next {109 102} Next {109 103} Next {109 104} Next {109 105} Next {109 106} Next {109 107} Next {109 108} Next {109 109} Next {109 110} Next {109 111} Next {109 112} Next {109 113} Scroll_Forward {109 114} Next {109 115} Next {109 116} Next {109 117} Next {109 118} Next {109 119} Next {109 120} Next {109 121} Next {109 122} Next {109 123} Next {109 124} Next {109 125} Next {109 126} Next {109 127} Next {110 0} Insert {110 1} Insert {110 2} Insert {110 3} Insert {110 4} Insert {110 5} Insert {110 6} Insert {110 7} Insert {110 8} Insert {110 9} Insert {110 10} Insert {110 11} Insert {110 12} Insert {110 13} Insert {110 14} Insert {110 15} Insert {110 16} Insert {110 17} Insert {110 18} Insert {110 19} Insert {110 20} Insert {110 21} Insert {110 22} Insert {110 23} Insert {110 24} Insert {110 25} Insert {110 26} Insert {110 27} Insert {110 28} Insert {110 29} Insert {110 30} Insert {110 31} Insert {110 32} Insert {110 33} Insert {110 34} Insert {110 35} Insert {110 36} Insert {110 37} Insert {110 38} Insert {110 39} Insert {110 40} Insert {110 41} Insert {110 42} Insert {110 43} Insert {110 44} Insert {110 45} Insert {110 46} Insert {110 47} Insert {110 48} Insert {110 49} Insert {110 50} Insert {110 51} Insert {110 52} Insert {110 53} Insert {110 54} Insert {110 55} Insert {110 56} Insert {110 57} Insert {110 58} Insert {110 59} Insert {110 60} Insert {110 61} Insert {110 62} Insert {110 63} Insert {110 64} Insert {110 65} Insert {110 66} Insert {110 67} Insert {110 68} Insert {110 69} Insert {110 70} Insert {110 71} Insert {110 72} Insert {110 73} Insert {110 74} Insert {110 75} Insert {110 76} Insert {110 77} Insert {110 78} Insert {110 79} Insert {110 80} Insert {110 81} Insert {110 82} Insert {110 83} Insert {110 84} Insert {110 85} Insert {110 86} Insert {110 87} Insert {110 88} Insert {110 89} Insert {110 90} Insert {110 91} Insert {110 92} Insert {110 93} Insert {110 94} Insert {110 95} Insert {110 96} Insert {110 97} Insert {110 98} Insert {110 99} Insert {110 100} Insert {110 101} Insert {110 102} Insert {110 103} Insert {110 104} Insert {110 105} Insert {110 106} Insert {110 107} Insert {110 108} Insert {110 109} Insert {110 110} Insert {110 111} Insert {110 112} Insert {110 113} Insert {110 114} Insert {110 115} Insert {110 116} Insert {110 117} Insert {110 118} Insert {110 119} Insert {110 120} Insert {110 121} Insert {110 122} Insert {110 123} Insert {110 124} Insert {110 125} Insert {110 126} Insert {110 127} Insert {111 0} Remove {111 1} Remove {111 2} Remove {111 3} Remove {111 4} Remove {111 5} Remove {111 6} Boot {111 7} Remove {111 8} Remove {111 9} Remove {111 10} Remove {111 11} Remove {111 12} Boot {111 13} Remove {111 14} Boot {111 15} Remove {111 16} Remove {111 17} Remove {111 18} Remove {111 19} Remove {111 20} Remove {111 21} Remove {111 22} Boot {111 23} Remove {111 24} Remove {111 25} Remove {111 26} Remove {111 27} Remove {111 28} Boot {111 29} Remove {111 30} Boot {111 31} Remove {111 32} Remove {111 33} Remove {111 34} Remove {111 35} Remove {111 36} Remove {111 37} Remove {111 38} Boot {111 39} Remove {111 40} Remove {111 41} Remove {111 42} Remove {111 43} Remove {111 44} Boot {111 45} Remove {111 46} Boot {111 47} Remove {111 48} Remove {111 49} Remove {111 50} Remove {111 51} Remove {111 52} Remove {111 53} Remove {111 54} Boot {111 55} Remove {111 56} Remove {111 57} Remove {111 58} Remove {111 59} Remove {111 60} Boot {111 61} Remove {111 62} Boot {111 63} Remove {111 64} Remove {111 65} Remove {111 66} Remove {111 67} Remove {111 68} Remove {111 69} Remove {111 70} Boot {111 71} Remove {111 72} Remove {111 73} Remove {111 74} Remove {111 75} Remove {111 76} Boot {111 77} Remove {111 78} Boot {111 79} Remove {111 80} Remove {111 81} Remove {111 82} Remove {111 83} Remove {111 84} Remove {111 85} Remove {111 86} Boot {111 87} Remove {111 88} Remove {111 89} Remove {111 90} Remove {111 91} Remove {111 92} Boot {111 93} Remove {111 94} Boot {111 95} Remove {111 96} Remove {111 97} Remove {111 98} Remove {111 99} Remove {111 100} Remove {111 101} Remove {111 102} Boot {111 103} Remove {111 104} Remove {111 105} Remove {111 106} Remove {111 107} Remove {111 108} Boot {111 109} Remove {111 110} Boot {111 111} Remove {111 112} Remove {111 113} Remove {111 114} Remove {111 115} Remove {111 116} Remove {111 117} Remove {111 118} Boot {111 119} Remove {111 120} Remove {111 121} Remove {111 122} Remove {111 123} Remove {111 124} Boot {111 125} Remove {111 126} Boot {111 127} Remove {112 0} Macro {112 1} Macro {112 2} Macro {112 3} Macro {112 4} Macro {112 5} Macro {112 6} Macro {113 0} F13 {113 1} F13 {113 2} F13 {113 3} F13 {113 4} F13 {113 5} F13 {113 6} F13 {114 0} F14 {114 1} F14 {114 2} F14 {114 3} F14 {114 4} F14 {114 5} F14 {114 6} F14 {115 0} Help {115 1} Help {115 2} Help {115 3} Help {115 4} Help {115 5} Help {115 6} Help {116 0} Do {116 1} Do {116 2} Do {116 3} Do {116 4} Do {116 5} Do {116 6} Do {117 0} F17 {117 1} F17 {117 2} F17 {117 3} F17 {117 4} F17 {117 5} F17 {117 6} F17 {118 0} KP_MinPlus {118 1} KP_MinPlus {118 2} KP_MinPlus {118 3} KP_MinPlus {118 4} KP_MinPlus {118 5} KP_MinPlus {118 6} KP_MinPlus {119 0} Pause {119 1} Pause {119 2} Pause {119 3} Pause {119 4} Break {119 5} Break {119 6} Break {119 7} Break {119 8} Pause {119 9} Pause {119 10} Pause {119 11} Pause {119 12} Break {119 13} Break {119 14} Break {119 15} Break {119 16} Pause {119 17} Pause {119 18} Pause {119 19} Pause {119 20} Break {119 21} Break {119 22} Break {119 23} Break {119 24} Pause {119 25} Pause {119 26} Pause {119 27} Pause {119 28} Break {119 29} Break {119 30} Break {119 31} Break {119 32} Pause {119 33} Pause {119 34} Pause {119 35} Pause {119 36} Break {119 37} Break {119 38} Break {119 39} Break {119 40} Pause {119 41} Pause {119 42} Pause {119 43} Pause {119 44} Break {119 45} Break {119 46} Break {119 47} Break {119 48} Pause {119 49} Pause {119 50} Pause {119 51} Pause {119 52} Break {119 53} Break {119 54} Break {119 55} Break {119 56} Pause {119 57} Pause {119 58} Pause {119 59} Pause {119 60} Break {119 61} Break {119 62} Break {119 63} Break {119 64} Pause {119 65} Pause {119 66} Pause {119 67} Pause {119 68} Break {119 69} Break {119 70} Break {119 71} Break {119 72} Pause {119 73} Pause {119 74} Pause {119 75} Pause {119 76} Break {119 77} Break {119 78} Break {119 79} Break {119 80} Pause {119 81} Pause {119 82} Pause {119 83} Pause {119 84} Break {119 85} Break {119 86} Break {119 87} Break {119 88} Pause {119 89} Pause {119 90} Pause {119 91} Pause {119 92} Break {119 93} Break {119 94} Break {119 95} Break {119 96} Pause {119 97} Pause {119 98} Pause {119 99} Pause {119 100} Break {119 101} Break {119 102} Break {119 103} Break {119 104} Pause {119 105} Pause {119 106} Pause {119 107} Pause {119 108} Break {119 109} Break {119 110} Break {119 111} Break {119 112} Pause {119 113} Pause {119 114} Pause {119 115} Pause {119 116} Break {119 117} Break {119 118} Break {119 119} Break {119 120} Pause {119 121} Pause {119 122} Pause {119 123} Pause {119 124} Break {119 125} Break {119 126} Break {119 127} Break {121 0} KP_Period {121 1} KP_Period {121 2} KP_Period {121 3} KP_Period {121 4} KP_Period {121 5} KP_Period {121 6} KP_Period {121 7} KP_Period {121 8} KP_Period {121 9} KP_Period {121 10} KP_Period {121 11} KP_Period {121 12} KP_Period {121 13} KP_Period {121 14} KP_Period {121 15} KP_Period {121 16} KP_Period {121 17} KP_Period {121 18} KP_Period {121 19} KP_Period {121 20} KP_Period {121 21} KP_Period {121 22} KP_Period {121 23} KP_Period {121 24} KP_Period {121 25} KP_Period {121 26} KP_Period {121 27} KP_Period {121 28} KP_Period {121 29} KP_Period {121 30} KP_Period {121 31} KP_Period {121 32} KP_Period {121 33} KP_Period {121 34} KP_Period {121 35} KP_Period {121 36} KP_Period {121 37} KP_Period {121 38} KP_Period {121 39} KP_Period {121 40} KP_Period {121 41} KP_Period {121 42} KP_Period {121 43} KP_Period {121 44} KP_Period {121 45} KP_Period {121 46} KP_Period {121 47} KP_Period {121 48} KP_Period {121 49} KP_Period {121 50} KP_Period {121 51} KP_Period {121 52} KP_Period {121 53} KP_Period {121 54} KP_Period {121 55} KP_Period {121 56} KP_Period {121 57} KP_Period {121 58} KP_Period {121 59} KP_Period {121 60} KP_Period {121 61} KP_Period {121 62} KP_Period {121 63} KP_Period {121 64} KP_Period {121 65} KP_Period {121 66} KP_Period {121 67} KP_Period {121 68} KP_Period {121 69} KP_Period {121 70} KP_Period {121 71} KP_Period {121 72} KP_Period {121 73} KP_Period {121 74} KP_Period {121 75} KP_Period {121 76} KP_Period {121 77} KP_Period {121 78} KP_Period {121 79} KP_Period {121 80} KP_Period {121 81} KP_Period {121 82} KP_Period {121 83} KP_Period {121 84} KP_Period {121 85} KP_Period {121 86} KP_Period {121 87} KP_Period {121 88} KP_Period {121 89} KP_Period {121 90} KP_Period {121 91} KP_Period {121 92} KP_Period {121 93} KP_Period {121 94} KP_Period {121 95} KP_Period {121 96} KP_Period {121 97} KP_Period {121 98} KP_Period {121 99} KP_Period {121 100} KP_Period {121 101} KP_Period {121 102} KP_Period {121 103} KP_Period {121 104} KP_Period {121 105} KP_Period {121 106} KP_Period {121 107} KP_Period {121 108} KP_Period {121 109} KP_Period {121 110} KP_Period {121 111} KP_Period {121 112} KP_Period {121 113} KP_Period {121 114} KP_Period {121 115} KP_Period {121 116} KP_Period {121 117} KP_Period {121 118} KP_Period {121 119} KP_Period {121 120} KP_Period {121 121} KP_Period {121 122} KP_Period {121 123} KP_Period {121 124} KP_Period {121 125} KP_Period {121 126} KP_Period {121 127} KP_Period {125 0} Alt {125 1} Alt {125 2} Alt {125 3} Alt {125 4} Alt {125 5} Alt {125 6} Alt {125 7} Alt {125 8} Alt {125 9} Alt {125 10} Alt {125 11} Alt {125 12} Alt {125 13} Alt {125 14} Alt {125 15} Alt {125 16} Alt {125 17} Alt {125 18} Alt {125 19} Alt {125 20} Alt {125 21} Alt {125 22} Alt {125 23} Alt {125 24} Alt {125 25} Alt {125 26} Alt {125 27} Alt {125 28} Alt {125 29} Alt {125 30} Alt {125 31} Alt {125 32} Alt {125 33} Alt {125 34} Alt {125 35} Alt {125 36} Alt {125 37} Alt {125 38} Alt {125 39} Alt {125 40} Alt {125 41} Alt {125 42} Alt {125 43} Alt {125 44} Alt {125 45} Alt {125 46} Alt {125 47} Alt {125 48} Alt {125 49} Alt {125 50} Alt {125 51} Alt {125 52} Alt {125 53} Alt {125 54} Alt {125 55} Alt {125 56} Alt {125 57} Alt {125 58} Alt {125 59} Alt {125 60} Alt {125 61} Alt {125 62} Alt {125 63} Alt {125 64} Alt {125 65} Alt {125 66} Alt {125 67} Alt {125 68} Alt {125 69} Alt {125 70} Alt {125 71} Alt {125 72} Alt {125 73} Alt {125 74} Alt {125 75} Alt {125 76} Alt {125 77} Alt {125 78} Alt {125 79} Alt {125 80} Alt {125 81} Alt {125 82} Alt {125 83} Alt {125 84} Alt {125 85} Alt {125 86} Alt {125 87} Alt {125 88} Alt {125 89} Alt {125 90} Alt {125 91} Alt {125 92} Alt {125 93} Alt {125 94} Alt {125 95} Alt {125 96} Alt {125 97} Alt {125 98} Alt {125 99} Alt {125 100} Alt {125 101} Alt {125 102} Alt {125 103} Alt {125 104} Alt {125 105} Alt {125 106} Alt {125 107} Alt {125 108} Alt {125 109} Alt {125 110} Alt {125 111} Alt {125 112} Alt {125 113} Alt {125 114} Alt {125 115} Alt {125 116} Alt {125 117} Alt {125 118} Alt {125 119} Alt {125 120} Alt {125 121} Alt {125 122} Alt {125 123} Alt {125 124} Alt {125 125} Alt {125 126} Alt {125 127} Alt {126 0} Alt {126 1} Alt {126 2} Alt {126 3} Alt {126 4} Alt {126 5} Alt {126 6} Alt {126 7} Alt {126 8} Alt {126 9} Alt {126 10} Alt {126 11} Alt {126 12} Alt {126 13} Alt {126 14} Alt {126 15} Alt {126 16} Alt {126 17} Alt {126 18} Alt {126 19} Alt {126 20} Alt {126 21} Alt {126 22} Alt {126 23} Alt {126 24} Alt {126 25} Alt {126 26} Alt {126 27} Alt {126 28} Alt {126 29} Alt {126 30} Alt {126 31} Alt {126 32} Alt {126 33} Alt {126 34} Alt {126 35} Alt {126 36} Alt {126 37} Alt {126 38} Alt {126 39} Alt {126 40} Alt {126 41} Alt {126 42} Alt {126 43} Alt {126 44} Alt {126 45} Alt {126 46} Alt {126 47} Alt {126 48} Alt {126 49} Alt {126 50} Alt {126 51} Alt {126 52} Alt {126 53} Alt {126 54} Alt {126 55} Alt {126 56} Alt {126 57} Alt {126 58} Alt {126 59} Alt {126 60} Alt {126 61} Alt {126 62} Alt {126 63} Alt {126 64} Alt {126 65} Alt {126 66} Alt {126 67} Alt {126 68} Alt {126 69} Alt {126 70} Alt {126 71} Alt {126 72} Alt {126 73} Alt {126 74} Alt {126 75} Alt {126 76} Alt {126 77} Alt {126 78} Alt {126 79} Alt {126 80} Alt {126 81} Alt {126 82} Alt {126 83} Alt {126 84} Alt {126 85} Alt {126 86} Alt {126 87} Alt {126 88} Alt {126 89} Alt {126 90} Alt {126 91} Alt {126 92} Alt {126 93} Alt {126 94} Alt {126 95} Alt {126 96} Alt {126 97} Alt {126 98} Alt {126 99} Alt {126 100} Alt {126 101} Alt {126 102} Alt {126 103} Alt {126 104} Alt {126 105} Alt {126 106} Alt {126 107} Alt {126 108} Alt {126 109} Alt {126 110} Alt {126 111} Alt {126 112} Alt {126 113} Alt {126 114} Alt {126 115} Alt {126 116} Alt {126 117} Alt {126 118} Alt {126 119} Alt {126 120} Alt {126 121} Alt {126 122} Alt {126 123} Alt {126 124} Alt {126 125} Alt {126 126} Alt {126 127} Alt} {{2 0} 1 {2 1} ! {2 2} 1 {2 3} ! {2 4} 1 {2 5} ! {2 6} 1 {2 7} ! {2 8} 1 {2 9} ! {2 10} 1 {2 11} ! {2 12} 1 {2 13} ! {2 14} 1 {2 15} ! {2 16} 1 {2 17} ! {2 18} 1 {2 19} ! {2 20} 1 {2 21} ! {2 22} 1 {2 23} ! {2 24} 1 {2 25} ! {2 26} 1 {2 27} ! {2 28} 1 {2 29} ! {2 30} 1 {2 31} ! {2 32} 1 {2 33} ! {2 34} 1 {2 35} ! {2 36} 1 {2 37} ! {2 38} 1 {2 39} ! {2 40} 1 {2 41} ! {2 42} 1 {2 43} ! {2 44} 1 {2 45} ! {2 46} 1 {2 47} ! {2 48} 1 {2 49} ! {2 50} 1 {2 51} ! {2 52} 1 {2 53} ! {2 54} 1 {2 55} ! {2 56} 1 {2 57} ! {2 58} 1 {2 59} ! {2 60} 1 {2 61} ! {2 62} 1 {2 63} ! {3 0} 2 {3 1} @ {3 2} 2 {3 3} @ {3 4} 2 {3 5} @ {3 6} 2 {3 7} @ {3 8} 2 {3 9} @ {3 10} 2 {3 11} @ {3 12} 2 {3 13} @ {3 14} 2 {3 15} @ {3 16} 2 {3 17} @ {3 18} 2 {3 19} @ {3 20} 2 {3 21} @ {3 22} 2 {3 23} @ {3 24} 2 {3 25} @ {3 26} 2 {3 27} @ {3 28} 2 {3 29} @ {3 30} 2 {3 31} @ {4 0} 3 {4 1} # {4 2} 3 {4 3} # {4 4} 3 {4 5} # {4 6} 3 {4 7} # {4 8} 3 {4 9} # {4 10} 3 {4 11} # {4 12} 3 {4 13} # {4 14} 3 {4 15} # {4 16} 3 {4 17} # {4 18} 3 {4 19} # {4 20} 3 {4 21} # {4 22} 3 {4 23} # {4 24} 3 {4 25} # {4 26} 3 {4 27} # {4 28} 3 {4 29} # {4 30} 3 {4 31} # {4 32} 3 {4 33} # {4 34} 3 {4 35} # {4 36} 3 {4 37} # {4 38} 3 {4 39} # {4 40} 3 {4 41} # {4 42} 3 {4 43} # {4 44} 3 {4 45} # {4 46} 3 {4 47} # {4 48} 3 {4 49} # {4 50} 3 {4 51} # {4 52} 3 {4 53} # {4 54} 3 {4 55} # {4 56} 3 {4 57} # {4 58} 3 {4 59} # {4 60} 3 {4 61} # {4 62} 3 {4 63} # {5 0} 4 {5 1} {$} {5 2} 4 {5 3} {$} {5 4} 4 {5 5} {$} {5 6} 4 {5 7} {$} {5 8} 4 {5 9} {$} {5 10} 4 {5 11} {$} {5 12} 4 {5 13} {$} {5 14} 4 {5 15} {$} {5 16} 4 {5 17} {$} {5 18} 4 {5 19} {$} {5 20} 4 {5 21} {$} {5 22} 4 {5 23} {$} {5 24} 4 {5 25} {$} {5 26} 4 {5 27} {$} {5 28} 4 {5 29} {$} {5 30} 4 {5 31} {$} {5 32} 4 {5 33} {$} {5 34} 4 {5 35} {$} {5 36} 4 {5 37} {$} {5 38} 4 {5 39} {$} {5 40} 4 {5 41} {$} {5 42} 4 {5 43} {$} {5 44} 4 {5 45} {$} {5 46} 4 {5 47} {$} {5 48} 4 {5 49} {$} {5 50} 4 {5 51} {$} {5 52} 4 {5 53} {$} {5 54} 4 {5 55} {$} {5 56} 4 {5 57} {$} {5 58} 4 {5 59} {$} {5 60} 4 {5 61} {$} {5 62} 4 {5 63} {$} {6 0} 5 {6 1} % {6 2} 5 {6 3} % {6 4} 5 {6 5} % {6 6} 5 {6 7} % {6 8} 5 {6 9} % {6 10} 5 {6 11} % {6 12} 5 {6 13} % {6 14} 5 {6 15} % {6 16} 5 {6 17} % {6 18} 5 {6 19} % {6 20} 5 {6 21} % {6 22} 5 {6 23} % {6 24} 5 {6 25} % {6 26} 5 {6 27} % {6 28} 5 {6 29} % {6 30} 5 {6 31} % {6 32} 5 {6 33} % {6 34} 5 {6 35} % {6 36} 5 {6 37} % {6 38} 5 {6 39} % {6 40} 5 {6 41} % {6 42} 5 {6 43} % {6 44} 5 {6 45} % {6 46} 5 {6 47} % {6 48} 5 {6 49} % {6 50} 5 {6 51} % {6 52} 5 {6 53} % {6 54} 5 {6 55} % {6 56} 5 {6 57} % {6 58} 5 {6 59} % {6 60} 5 {6 61} % {6 62} 5 {6 63} % {7 0} 6 {7 1} ^ {7 2} 6 {7 3} ^ {7 4} 6 {7 5} ^ {7 6} 6 {7 7} ^ {7 8} 6 {7 9} ^ {7 10} 6 {7 11} ^ {7 12} 6 {7 13} ^ {7 14} 6 {7 15} ^ {7 16} 6 {7 17} ^ {7 18} 6 {7 19} ^ {7 20} 6 {7 21} ^ {7 22} 6 {7 23} ^ {7 24} 6 {7 25} ^ {7 26} 6 {7 27} ^ {7 28} 6 {7 29} ^ {7 30} 6 {7 31} ^ {8 0} 7 {8 1} & {8 2} 7 {8 3} & {8 4} 7 {8 5} & {8 6} 7 {8 7} & {8 8} 7 {8 9} & {8 10} 7 {8 11} & {8 12} 7 {8 13} & {8 14} 7 {8 15} & {8 16} 7 {8 17} & {8 18} 7 {8 19} & {8 20} 7 {8 21} & {8 22} 7 {8 23} & {8 24} 7 {8 25} & {8 26} 7 {8 27} & {8 28} 7 {8 29} & {8 30} 7 {8 31} & {8 32} 7 {8 33} & {8 34} 7 {8 35} & {8 36} 7 {8 37} & {8 38} 7 {8 39} & {8 40} 7 {8 41} & {8 42} 7 {8 43} & {8 44} 7 {8 45} & {8 46} 7 {8 47} & {8 48} 7 {8 49} & {8 50} 7 {8 51} & {8 52} 7 {8 53} & {8 54} 7 {8 55} & {8 56} 7 {8 57} & {8 58} 7 {8 59} & {8 60} 7 {8 61} & {8 62} 7 {8 63} & {9 0} 8 {9 1} * {9 2} 8 {9 3} * {9 4} 8 {9 5} * {9 6} 8 {9 7} * {9 8} 8 {9 9} * {9 10} 8 {9 11} * {9 12} 8 {9 13} * {9 14} 8 {9 15} * {9 16} 8 {9 17} * {9 18} 8 {9 19} * {9 20} 8 {9 21} * {9 22} 8 {9 23} * {9 24} 8 {9 25} * {9 26} 8 {9 27} * {9 28} 8 {9 29} * {9 30} 8 {9 31} * {9 32} 8 {9 33} * {9 34} 8 {9 35} * {9 36} 8 {9 37} * {9 38} 8 {9 39} * {9 40} 8 {9 41} * {9 42} 8 {9 43} * {9 44} 8 {9 45} * {9 46} 8 {9 47} * {9 48} 8 {9 49} * {9 50} 8 {9 51} * {9 52} 8 {9 53} * {9 54} 8 {9 55} * {9 56} 8 {9 57} * {9 58} 8 {9 59} * {9 60} 8 {9 61} * {9 62} 8 {9 63} * {10 0} 9 {10 1} ( {10 2} 9 {10 3} ( {10 4} 9 {10 5} ( {10 6} 9 {10 7} ( {10 8} 9 {10 9} ( {10 10} 9 {10 11} ( {10 12} 9 {10 13} ( {10 14} 9 {10 15} ( {10 16} 9 {10 17} ( {10 18} 9 {10 19} ( {10 20} 9 {10 21} ( {10 22} 9 {10 23} ( {10 24} 9 {10 25} ( {10 26} 9 {10 27} ( {10 28} 9 {10 29} ( {10 30} 9 {10 31} ( {10 32} 9 {10 33} ( {10 34} 9 {10 35} ( {10 36} 9 {10 37} ( {10 38} 9 {10 39} ( {10 40} 9 {10 41} ( {10 42} 9 {10 43} ( {10 44} 9 {10 45} ( {10 46} 9 {10 47} ( {10 48} 9 {10 49} ( {10 50} 9 {10 51} ( {10 52} 9 {10 53} ( {10 54} 9 {10 55} ( {10 56} 9 {10 57} ( {10 58} 9 {10 59} ( {10 60} 9 {10 61} ( {10 62} 9 {10 63} ( {11 0} 0 {11 1} ) {11 2} 0 {11 3} ) {11 4} 0 {11 5} ) {11 6} 0 {11 7} ) {11 8} 0 {11 9} ) {11 10} 0 {11 11} ) {11 12} 0 {11 13} ) {11 14} 0 {11 15} ) {11 16} 0 {11 17} ) {11 18} 0 {11 19} ) {11 20} 0 {11 21} ) {11 22} 0 {11 23} ) {11 24} 0 {11 25} ) {11 26} 0 {11 27} ) {11 28} 0 {11 29} ) {11 30} 0 {11 31} ) {11 32} 0 {11 33} ) {11 34} 0 {11 35} ) {11 36} 0 {11 37} ) {11 38} 0 {11 39} ) {11 40} 0 {11 41} ) {11 42} 0 {11 43} ) {11 44} 0 {11 45} ) {11 46} 0 {11 47} ) {11 48} 0 {11 49} ) {11 50} 0 {11 51} ) {11 52} 0 {11 53} ) {11 54} 0 {11 55} ) {11 56} 0 {11 57} ) {11 58} 0 {11 59} ) {11 60} 0 {11 61} ) {11 62} 0 {11 63} ) {12 0} - {12 1} _ {12 2} - {12 3} _ {12 4} - {12 5} _ {12 6} - {12 7} _ {12 8} - {12 9} _ {12 10} - {12 11} _ {12 12} - {12 13} _ {12 14} - {12 15} _ {12 16} - {12 17} _ {12 18} - {12 19} _ {12 20} - {12 21} _ {12 22} - {12 23} _ {12 24} - {12 25} _ {12 26} - {12 27} _ {12 28} - {12 29} _ {12 30} - {12 31} _ {13 0} = {13 1} + {13 2} = {13 3} + {13 4} = {13 5} + {13 6} = {13 7} + {13 8} = {13 9} + {13 10} = {13 11} + {13 12} = {13 13} + {13 14} = {13 15} + {13 16} = {13 17} + {13 18} = {13 19} + {13 20} = {13 21} + {13 22} = {13 23} + {13 24} = {13 25} + {13 26} = {13 27} + {13 28} = {13 29} + {13 30} = {13 31} + {13 32} = {13 33} + {13 34} = {13 35} + {13 36} = {13 37} + {13 38} = {13 39} + {13 40} = {13 41} + {13 42} = {13 43} + {13 44} = {13 45} + {13 46} = {13 47} + {13 48} = {13 49} + {13 50} = {13 51} + {13 52} = {13 53} + {13 54} = {13 55} + {13 56} = {13 57} + {13 58} = {13 59} + {13 60} = {13 61} + {13 62} = {13 63} + {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} q {16 5} Q {16 6} q {16 7} Q {16 8} q {16 9} Q {16 10} q {16 11} Q {16 12} q {16 13} Q {16 14} q {16 15} Q {16 16} Q {16 17} q {16 18} Q {16 19} q {16 20} Q {16 21} q {16 22} Q {16 23} q {16 24} Q {16 25} q {16 26} Q {16 27} q {16 28} Q {16 29} q {16 30} Q {16 31} q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} w {17 5} W {17 6} w {17 7} W {17 8} w {17 9} W {17 10} w {17 11} W {17 12} w {17 13} W {17 14} w {17 15} W {17 16} W {17 17} w {17 18} W {17 19} w {17 20} W {17 21} w {17 22} W {17 23} w {17 24} W {17 25} w {17 26} W {17 27} w {17 28} W {17 29} w {17 30} W {17 31} w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} e {18 5} E {18 6} e {18 7} E {18 8} e {18 9} E {18 10} e {18 11} E {18 12} e {18 13} E {18 14} e {18 15} E {18 16} E {18 17} e {18 18} E {18 19} e {18 20} E {18 21} e {18 22} E {18 23} e {18 24} E {18 25} e {18 26} E {18 27} e {18 28} E {18 29} e {18 30} E {18 31} e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} r {19 5} R {19 6} r {19 7} R {19 8} r {19 9} R {19 10} r {19 11} R {19 12} r {19 13} R {19 14} r {19 15} R {19 16} R {19 17} r {19 18} R {19 19} r {19 20} R {19 21} r {19 22} R {19 23} r {19 24} R {19 25} r {19 26} R {19 27} r {19 28} R {19 29} r {19 30} R {19 31} r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} t {20 5} T {20 6} t {20 7} T {20 8} t {20 9} T {20 10} t {20 11} T {20 12} t {20 13} T {20 14} t {20 15} T {20 16} T {20 17} t {20 18} T {20 19} t {20 20} T {20 21} t {20 22} T {20 23} t {20 24} T {20 25} t {20 26} T {20 27} t {20 28} T {20 29} t {20 30} T {20 31} t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} y {21 5} Y {21 6} y {21 7} Y {21 8} y {21 9} Y {21 10} y {21 11} Y {21 12} y {21 13} Y {21 14} y {21 15} Y {21 16} Y {21 17} y {21 18} Y {21 19} y {21 20} Y {21 21} y {21 22} Y {21 23} y {21 24} Y {21 25} y {21 26} Y {21 27} y {21 28} Y {21 29} y {21 30} Y {21 31} y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} u {22 5} U {22 6} u {22 7} U {22 8} u {22 9} U {22 10} u {22 11} U {22 12} u {22 13} U {22 14} u {22 15} U {22 16} U {22 17} u {22 18} U {22 19} u {22 20} U {22 21} u {22 22} U {22 23} u {22 24} U {22 25} u {22 26} U {22 27} u {22 28} U {22 29} u {22 30} U {22 31} u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} i {23 5} I {23 6} i {23 7} I {23 8} i {23 9} I {23 10} i {23 11} I {23 12} i {23 13} I {23 14} i {23 15} I {23 16} I {23 17} i {23 18} I {23 19} i {23 20} I {23 21} i {23 22} I {23 23} i {23 24} I {23 25} i {23 26} I {23 27} i {23 28} I {23 29} i {23 30} I {23 31} i {24 0} o {24 1} O {24 2} o {24 3} O {24 4} o {24 5} O {24 6} o {24 7} O {24 8} o {24 9} O {24 10} o {24 11} O {24 12} o {24 13} O {24 14} o {24 15} O {24 16} O {24 17} o {24 18} O {24 19} o {24 20} O {24 21} o {24 22} O {24 23} o {24 24} O {24 25} o {24 26} O {24 27} o {24 28} O {24 29} o {24 30} O {24 31} o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} p {25 5} P {25 6} p {25 7} P {25 8} p {25 9} P {25 10} p {25 11} P {25 12} p {25 13} P {25 14} p {25 15} P {25 16} P {25 17} p {25 18} P {25 19} p {25 20} P {25 21} p {25 22} P {25 23} p {25 24} P {25 25} p {25 26} P {25 27} p {25 28} P {25 29} p {25 30} P {25 31} p {26 0} {[} {26 1} \{ {26 2} {[} {26 3} \{ {26 4} {[} {26 5} \{ {26 6} {[} {26 7} \{ {26 8} {[} {26 9} \{ {26 10} {[} {26 11} \{ {26 12} {[} {26 13} \{ {26 14} {[} {26 15} \{ {26 16} {[} {26 17} \{ {26 18} {[} {26 19} \{ {26 20} {[} {26 21} \{ {26 22} {[} {26 23} \{ {26 24} {[} {26 25} \{ {26 26} {[} {26 27} \{ {26 28} {[} {26 29} \{ {26 30} {[} {26 31} \{ {27 0} \] {27 1} \} {27 2} \] {27 3} \} {27 4} \] {27 5} \} {27 6} \] {27 7} \} {27 8} \] {27 9} \} {27 10} \] {27 11} \} {27 12} \] {27 13} \} {27 14} \] {27 15} \} {27 16} \] {27 17} \} {27 18} \] {27 19} \} {27 20} \] {27 21} \} {27 22} \] {27 23} \} {27 24} \] {27 25} \} {27 26} \] {27 27} \} {27 28} \] {27 29} \} {27 30} \] {27 31} \} {30 0} a {30 1} A {30 2} a {30 3} A {30 4} a {30 5} A {30 6} a {30 7} A {30 8} a {30 9} A {30 10} a {30 11} A {30 12} a {30 13} A {30 14} a {30 15} A {30 16} A {30 17} a {30 18} A {30 19} a {30 20} A {30 21} a {30 22} A {30 23} a {30 24} A {30 25} a {30 26} A {30 27} a {30 28} A {30 29} a {30 30} A {30 31} a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} s {31 5} S {31 6} s {31 7} S {31 8} s {31 9} S {31 10} s {31 11} S {31 12} s {31 13} S {31 14} s {31 15} S {31 16} S {31 17} s {31 18} S {31 19} s {31 20} S {31 21} s {31 22} S {31 23} s {31 24} S {31 25} s {31 26} S {31 27} s {31 28} S {31 29} s {31 30} S {31 31} s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} d {32 5} D {32 6} d {32 7} D {32 8} d {32 9} D {32 10} d {32 11} D {32 12} d {32 13} D {32 14} d {32 15} D {32 16} D {32 17} d {32 18} D {32 19} d {32 20} D {32 21} d {32 22} D {32 23} d {32 24} D {32 25} d {32 26} D {32 27} d {32 28} D {32 29} d {32 30} D {32 31} d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} f {33 5} F {33 6} f {33 7} F {33 8} f {33 9} F {33 10} f {33 11} F {33 12} f {33 13} F {33 14} f {33 15} F {33 16} F {33 17} f {33 18} F {33 19} f {33 20} F {33 21} f {33 22} F {33 23} f {33 24} F {33 25} f {33 26} F {33 27} f {33 28} F {33 29} f {33 30} F {33 31} f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} g {34 5} G {34 6} g {34 7} G {34 8} g {34 9} G {34 10} g {34 11} G {34 12} g {34 13} G {34 14} g {34 15} G {34 16} G {34 17} g {34 18} G {34 19} g {34 20} G {34 21} g {34 22} G {34 23} g {34 24} G {34 25} g {34 26} G {34 27} g {34 28} G {34 29} g {34 30} G {34 31} g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} h {35 5} H {35 6} h {35 7} H {35 8} h {35 9} H {35 10} h {35 11} H {35 12} h {35 13} H {35 14} h {35 15} H {35 16} H {35 17} h {35 18} H {35 19} h {35 20} H {35 21} h {35 22} H {35 23} h {35 24} H {35 25} h {35 26} H {35 27} h {35 28} H {35 29} h {35 30} H {35 31} h {36 0} j {36 1} J {36 2} j {36 3} J {36 4} j {36 5} J {36 6} j {36 7} J {36 8} j {36 9} J {36 10} j {36 11} J {36 12} j {36 13} J {36 14} j {36 15} J {36 16} J {36 17} j {36 18} J {36 19} j {36 20} J {36 21} j {36 22} J {36 23} j {36 24} J {36 25} j {36 26} J {36 27} j {36 28} J {36 29} j {36 30} J {36 31} j {37 0} k {37 1} K {37 2} k {37 3} K {37 4} k {37 5} K {37 6} k {37 7} K {37 8} k {37 9} K {37 10} k {37 11} K {37 12} k {37 13} K {37 14} k {37 15} K {37 16} K {37 17} k {37 18} K {37 19} k {37 20} K {37 21} k {37 22} K {37 23} k {37 24} K {37 25} k {37 26} K {37 27} k {37 28} K {37 29} k {37 30} K {37 31} k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} l {38 5} L {38 6} l {38 7} L {38 8} l {38 9} L {38 10} l {38 11} L {38 12} l {38 13} L {38 14} l {38 15} L {38 16} L {38 17} l {38 18} L {38 19} l {38 20} L {38 21} l {38 22} L {38 23} l {38 24} L {38 25} l {38 26} L {38 27} l {38 28} L {38 29} l {38 30} L {38 31} l {39 0} {;} {39 1} : {39 2} {;} {39 3} : {39 4} {;} {39 5} : {39 6} {;} {39 7} : {39 8} {;} {39 9} : {39 10} {;} {39 11} : {39 12} {;} {39 13} : {39 14} {;} {39 15} : {39 16} {;} {39 17} : {39 18} {;} {39 19} : {39 20} {;} {39 21} : {39 22} {;} {39 23} : {39 24} {;} {39 25} : {39 26} {;} {39 27} : {39 28} {;} {39 29} : {39 30} {;} {39 31} : {39 32} {;} {39 33} : {39 34} {;} {39 35} : {39 36} {;} {39 37} : {39 38} {;} {39 39} : {39 40} {;} {39 41} : {39 42} {;} {39 43} : {39 44} {;} {39 45} : {39 46} {;} {39 47} : {39 48} {;} {39 49} : {39 50} {;} {39 51} : {39 52} {;} {39 53} : {39 54} {;} {39 55} : {39 56} {;} {39 57} : {39 58} {;} {39 59} : {39 60} {;} {39 61} : {39 62} {;} {39 63} : {40 0} ' {40 1} {"} {40 2} ' {40 3} {"} {40 4} ' {40 5} {"} {40 6} ' {40 7} {"} {40 8} ' {40 9} {"} {40 10} ' {40 11} {"} {40 12} ' {40 13} {"} {40 14} ' {40 15} {"} {40 16} ' {40 17} {"} {40 18} ' {40 19} {"} {40 20} ' {40 21} {"} {40 22} ' {40 23} {"} {40 24} ' {40 25} {"} {40 26} ' {40 27} {"} {40 28} ' {40 29} {"} {40 30} ' {40 31} {"} {40 32} ' {40 33} {"} {40 34} ' {40 35} {"} {40 36} ' {40 37} {"} {40 38} ' {40 39} {"} {40 40} ' {40 41} {"} {40 42} ' {40 43} {"} {40 44} ' {40 45} {"} {40 46} ' {40 47} {"} {40 48} ' {40 49} {"} {40 50} ' {40 51} {"} {40 52} ' {40 53} {"} {40 54} ' {40 55} {"} {40 56} ' {40 57} {"} {40 58} ' {40 59} {"} {40 60} ' {40 61} {"} {40 62} ' {40 63} {"} {41 0} ` {41 1} ~ {41 2} ` {41 3} ~ {41 4} ` {41 5} ~ {41 6} ` {41 7} ~ {41 8} ` {41 9} ~ {41 10} ` {41 11} ~ {41 12} ` {41 13} ~ {41 14} ` {41 15} ~ {41 16} ` {41 17} ~ {41 18} ` {41 19} ~ {41 20} ` {41 21} ~ {41 22} ` {41 23} ~ {41 24} ` {41 25} ~ {41 26} ` {41 27} ~ {41 28} ` {41 29} ~ {41 30} ` {41 31} ~ {43 0} \\ {43 1} | {43 2} \\ {43 3} | {43 4} \\ {43 5} | {43 6} \\ {43 7} | {43 8} \\ {43 9} | {43 10} \\ {43 11} | {43 12} \\ {43 13} | {43 14} \\ {43 15} | {43 16} \\ {43 17} | {43 18} \\ {43 19} | {43 20} \\ {43 21} | {43 22} \\ {43 23} | {43 24} \\ {43 25} | {43 26} \\ {43 27} | {43 28} \\ {43 29} | {43 30} \\ {43 31} | {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} z {44 5} Z {44 6} z {44 7} Z {44 8} z {44 9} Z {44 10} z {44 11} Z {44 12} z {44 13} Z {44 14} z {44 15} Z {44 16} Z {44 17} z {44 18} Z {44 19} z {44 20} Z {44 21} z {44 22} Z {44 23} z {44 24} Z {44 25} z {44 26} Z {44 27} z {44 28} Z {44 29} z {44 30} Z {44 31} z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} x {45 5} X {45 6} x {45 7} X {45 8} x {45 9} X {45 10} x {45 11} X {45 12} x {45 13} X {45 14} x {45 15} X {45 16} X {45 17} x {45 18} X {45 19} x {45 20} X {45 21} x {45 22} X {45 23} x {45 24} X {45 25} x {45 26} X {45 27} x {45 28} X {45 29} x {45 30} X {45 31} x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} c {46 5} C {46 6} c {46 7} C {46 8} c {46 9} C {46 10} c {46 11} C {46 12} c {46 13} C {46 14} c {46 15} C {46 16} C {46 17} c {46 18} C {46 19} c {46 20} C {46 21} c {46 22} C {46 23} c {46 24} C {46 25} c {46 26} C {46 27} c {46 28} C {46 29} c {46 30} C {46 31} c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} v {47 5} V {47 6} v {47 7} V {47 8} v {47 9} V {47 10} v {47 11} V {47 12} v {47 13} V {47 14} v {47 15} V {47 16} V {47 17} v {47 18} V {47 19} v {47 20} V {47 21} v {47 22} V {47 23} v {47 24} V {47 25} v {47 26} V {47 27} v {47 28} V {47 29} v {47 30} V {47 31} v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} b {48 5} B {48 6} b {48 7} B {48 8} b {48 9} B {48 10} b {48 11} B {48 12} b {48 13} B {48 14} b {48 15} B {48 16} B {48 17} b {48 18} B {48 19} b {48 20} B {48 21} b {48 22} B {48 23} b {48 24} B {48 25} b {48 26} B {48 27} b {48 28} B {48 29} b {48 30} B {48 31} b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} n {49 5} N {49 6} n {49 7} N {49 8} n {49 9} N {49 10} n {49 11} N {49 12} n {49 13} N {49 14} n {49 15} N {49 16} N {49 17} n {49 18} N {49 19} n {49 20} N {49 21} n {49 22} N {49 23} n {49 24} N {49 25} n {49 26} N {49 27} n {49 28} N {49 29} n {49 30} N {49 31} n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} m {50 5} M {50 6} m {50 7} M {50 8} m {50 9} M {50 10} m {50 11} M {50 12} m {50 13} M {50 14} m {50 15} M {50 16} M {50 17} m {50 18} M {50 19} m {50 20} M {50 21} m {50 22} M {50 23} m {50 24} M {50 25} m {50 26} M {50 27} m {50 28} M {50 29} m {50 30} M {50 31} m {51 0} , {51 1} < {51 2} , {51 3} < {51 4} , {51 5} < {51 6} , {51 7} < {51 8} , {51 9} < {51 10} , {51 11} < {51 12} , {51 13} < {51 14} , {51 15} < {51 16} , {51 17} < {51 18} , {51 19} < {51 20} , {51 21} < {51 22} , {51 23} < {51 24} , {51 25} < {51 26} , {51 27} < {51 28} , {51 29} < {51 30} , {51 31} < {51 32} , {51 33} < {51 34} , {51 35} < {51 36} , {51 37} < {51 38} , {51 39} < {51 40} , {51 41} < {51 42} , {51 43} < {51 44} , {51 45} < {51 46} , {51 47} < {51 48} , {51 49} < {51 50} , {51 51} < {51 52} , {51 53} < {51 54} , {51 55} < {51 56} , {51 57} < {51 58} , {51 59} < {51 60} , {51 61} < {51 62} , {51 63} < {52 0} . {52 1} > {52 2} . {52 3} > {52 4} . {52 5} > {52 6} . {52 7} > {52 8} . {52 9} > {52 10} . {52 11} > {52 12} . {52 13} > {52 14} . {52 15} > {52 16} . {52 17} > {52 18} . {52 19} > {52 20} . {52 21} > {52 22} . {52 23} > {52 24} . {52 25} > {52 26} . {52 27} > {52 28} . {52 29} > {52 30} . {52 31} > {53 0} / {53 1} ? {53 2} / {53 3} ? {53 4} / {53 5} ? {53 6} / {53 7} ? {53 8} / {53 9} ? {53 10} / {53 11} ? {53 12} / {53 13} ? {53 14} / {53 15} ? {53 16} / {53 17} ? {53 18} / {53 19} ? {53 20} / {53 21} ? {53 22} / {53 23} ? {53 24} / {53 25} ? {53 26} / {53 27} ? {53 28} / {53 29} ? {53 30} / {53 31} ? {57 0} { } {57 1} { } {57 2} { } {57 3} { } {57 4} { } {57 5} { } {57 6} { } {57 7} { } {57 8} { } {57 9} { } {57 10} { } {57 11} { } {57 12} { } {57 13} { } {57 14} { } {57 15} { } {57 16} { } {57 17} { } {57 18} { } {57 19} { } {57 20} { } {57 21} { } {57 22} { } {57 23} { } {57 24} { } {57 25} { } {57 26} { } {57 27} { } {57 28} { } {57 29} { } {57 30} { } {57 31} { } {86 0} < {86 1} > {86 2} | {86 3} ¦ {86 4} > {86 5} < {86 6} > {86 7} | {86 8} ¦ {86 9} > {86 10} < {86 11} > {86 12} | {86 13} ¦ {86 14} > {86 15} < {86 16} > {86 17} | {86 18} ¦ {86 19} > {86 20} < {86 21} > {86 22} | {86 23} ¦ {86 24} > {86 25} < {86 26} > {86 27} | {86 28} ¦ {86 29} > {86 30} < {86 31} > {86 32} | {86 33} ¦ {86 34} > {86 35} < {86 36} > {86 37} | {86 38} ¦ {86 39} >}} keyboardFileno 68 grabber <C:cfiletRL0ox> cc ::<reference.<C______>.00000000000000000002>}}
when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd locale ()when /page/ is a keyboard with path /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd locale /locale/ \n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}} {keyboard /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd} {keyboardChannel ::aio.handle248 KEY_STATES {up down repeat} defaultKeymap {{{1 0} Escape {1 1} Escape {1 2} Escape {1 3} Escape {1 4} Escape {1 5} Escape {1 6} Escape {1 7} Escape {1 8} Meta_Escape {1 9} Meta_Escape {1 10} Meta_Escape {1 11} Meta_Escape {1 12} Meta_Escape {1 13} Meta_Escape {1 14} Meta_Escape {1 15} Meta_Escape {1 16} Escape {1 17} Escape {1 18} Escape {1 19} Escape {1 20} Escape {1 21} Escape {1 22} Escape {1 23} Escape {1 24} Meta_Escape {1 25} Meta_Escape {1 26} Meta_Escape {1 27} Meta_Escape {1 28} Meta_Escape {1 29} Meta_Escape {1 30} Meta_Escape {1 31} Meta_Escape {1 32} Escape {1 33} Escape {1 34} Escape {1 35} Escape {1 36} Escape {1 37} Escape {1 38} Escape {1 39} Escape {1 40} Meta_Escape {1 41} Meta_Escape {1 42} Meta_Escape {1 43} Meta_Escape {1 44} Meta_Escape {1 45} Meta_Escape {1 46} Meta_Escape {1 47} Meta_Escape {1 48} Escape {1 49} Escape {1 50} Escape {1 51} Escape {1 52} Escape {1 53} Escape {1 54} Escape {1 55} Escape {1 56} Meta_Escape {1 57} Meta_Escape {1 58} Meta_Escape {1 59} Meta_Escape {1 60} Meta_Escape {1 61} Meta_Escape {1 62} Meta_Escape {1 63} Meta_Escape {1 64} Escape {1 65} Escape {1 66} Escape {1 67} Escape {1 68} Escape {1 69} Escape {1 70} Escape {1 71} Escape {1 72} Meta_Escape {1 73} Meta_Escape {1 74} Meta_Escape {1 75} Meta_Escape {1 76} Meta_Escape {1 77} Meta_Escape {1 78} Meta_Escape {1 79} Meta_Escape {1 80} Escape {1 81} Escape {1 82} Escape {1 83} Escape {1 84} Escape {1 85} Escape {1 86} Escape {1 87} Escape {1 88} Meta_Escape {1 89} Meta_Escape {1 90} Meta_Escape {1 91} Meta_Escape {1 92} Meta_Escape {1 93} Meta_Escape {1 94} Meta_Escape {1 95} Meta_Escape {1 96} Escape {1 97} Escape {1 98} Escape {1 99} Escape {1 100} Escape {1 101} Escape {1 102} Escape {1 103} Escape {1 104} Meta_Escape {1 105} Meta_Escape {1 106} Meta_Escape {1 107} Meta_Escape {1 108} Meta_Escape {1 109} Meta_Escape {1 110} Meta_Escape {1 111} Meta_Escape {1 112} Escape {1 113} Escape {1 114} Escape {1 115} Escape {1 116} Escape {1 117} Escape {1 118} Escape {1 119} Escape {1 120} Meta_Escape {1 121} Meta_Escape {1 122} Meta_Escape {1 123} Meta_Escape {1 124} Meta_Escape {1 125} Meta_Escape {1 126} Meta_Escape {1 127} Meta_Escape {2 0} one {2 1} exclam {2 2} one {2 3} exclam {2 4} one {2 5} exclam {2 6} one {2 7} exclam {2 8} Meta_one {2 9} Meta_exclam {2 10} Meta_one {2 11} Meta_exclam {2 12} Meta_one {2 13} Meta_exclam {2 14} Meta_one {2 15} Meta_exclam {2 16} one {2 17} exclam {2 18} one {2 19} exclam {2 20} one {2 21} exclam {2 22} one {2 23} exclam {2 24} Meta_one {2 25} Meta_exclam {2 26} Meta_one {2 27} Meta_exclam {2 28} Meta_one {2 29} Meta_exclam {2 30} Meta_one {2 31} Meta_exclam {2 32} one {2 33} exclam {2 34} one {2 35} exclam {2 36} one {2 37} exclam {2 38} one {2 39} exclam {2 40} Meta_one {2 41} Meta_exclam {2 42} Meta_one {2 43} Meta_exclam {2 44} Meta_one {2 45} Meta_exclam {2 46} Meta_one {2 47} Meta_exclam {2 48} one {2 49} exclam {2 50} one {2 51} exclam {2 52} one {2 53} exclam {2 54} one {2 55} exclam {2 56} Meta_one {2 57} Meta_exclam {2 58} Meta_one {2 59} Meta_exclam {2 60} Meta_one {2 61} Meta_exclam {2 62} Meta_one {2 63} Meta_exclam {2 64} one {2 65} exclam {2 66} one {2 67} exclam {2 68} one {2 69} exclam {2 70} one {2 71} exclam {2 72} Meta_one {2 73} Meta_exclam {2 74} Meta_one {2 75} Meta_exclam {2 76} Meta_one {2 77} Meta_exclam {2 78} Meta_one {2 79} Meta_exclam {2 80} one {2 81} exclam {2 82} one {2 83} exclam {2 84} one {2 85} exclam {2 86} one {2 87} exclam {2 88} Meta_one {2 89} Meta_exclam {2 90} Meta_one {2 91} Meta_exclam {2 92} Meta_one {2 93} Meta_exclam {2 94} Meta_one {2 95} Meta_exclam {2 96} one {2 97} exclam {2 98} one {2 99} exclam {2 100} one {2 101} exclam {2 102} one {2 103} exclam {2 104} Meta_one {2 105} Meta_exclam {2 106} Meta_one {2 107} Meta_exclam {2 108} Meta_one {2 109} Meta_exclam {2 110} Meta_one {2 111} Meta_exclam {2 112} one {2 113} exclam {2 114} one {2 115} exclam {2 116} one {2 117} exclam {2 118} one {2 119} exclam {2 120} Meta_one {2 121} Meta_exclam {2 122} Meta_one {2 123} Meta_exclam {2 124} Meta_one {2 125} Meta_exclam {2 126} Meta_one {2 127} Meta_exclam {3 0} two {3 1} at {3 2} two {3 3} at {3 4} nul {3 5} nul {3 6} nul {3 7} nul {3 8} Meta_two {3 9} Meta_at {3 10} Meta_two {3 11} Meta_at {3 12} Meta_nul {3 13} Meta_nul {3 14} Meta_nul {3 15} Meta_nul {3 16} two {3 17} at {3 18} two {3 19} at {3 20} nul {3 21} nul {3 22} nul {3 23} nul {3 24} Meta_two {3 25} Meta_at {3 26} Meta_two {3 27} Meta_at {3 28} Meta_nul {3 29} Meta_nul {3 30} Meta_nul {3 31} Meta_nul {3 32} two {3 33} at {3 34} two {3 35} at {3 36} nul {3 37} nul {3 38} nul {3 39} nul {3 40} Meta_two {3 41} Meta_at {3 42} Meta_two {3 43} Meta_at {3 44} Meta_nul {3 45} Meta_nul {3 46} Meta_nul {3 47} Meta_nul {3 48} two {3 49} at {3 50} two {3 51} at {3 52} nul {3 53} nul {3 54} nul {3 55} nul {3 56} Meta_two {3 57} Meta_at {3 58} Meta_two {3 59} Meta_at {3 60} Meta_nul {3 61} Meta_nul {3 62} Meta_nul {3 63} Meta_nul {3 64} two {3 65} at {3 66} two {3 67} at {3 68} nul {3 69} nul {3 70} nul {3 71} nul {3 72} Meta_two {3 73} Meta_at {3 74} Meta_two {3 75} Meta_at {3 76} Meta_nul {3 77} Meta_nul {3 78} Meta_nul {3 79} Meta_nul {3 80} two {3 81} at {3 82} two {3 83} at {3 84} nul {3 85} nul {3 86} nul {3 87} nul {3 88} Meta_two {3 89} Meta_at {3 90} Meta_two {3 91} Meta_at {3 92} Meta_nul {3 93} Meta_nul {3 94} Meta_nul {3 95} Meta_nul {3 96} two {3 97} at {3 98} two {3 99} at {3 100} nul {3 101} nul {3 102} nul {3 103} nul {3 104} Meta_two {3 105} Meta_at {3 106} Meta_two {3 107} Meta_at {3 108} Meta_nul {3 109} Meta_nul {3 110} Meta_nul {3 111} Meta_nul {3 112} two {3 113} at {3 114} two {3 115} at {3 116} nul {3 117} nul {3 118} nul {3 119} nul {3 120} Meta_two {3 121} Meta_at {3 122} Meta_two {3 123} Meta_at {3 124} Meta_nul {3 125} Meta_nul {3 126} Meta_nul {3 127} Meta_nul {4 0} three {4 1} numbersign {4 2} three {4 3} numbersign {4 4} three {4 5} numbersign {4 6} three {4 7} numbersign {4 8} Meta_three {4 9} Meta_numbersign {4 10} Meta_three {4 11} Meta_numbersign {4 12} Meta_three {4 13} Meta_numbersign {4 14} Meta_three {4 15} Meta_numbersign {4 16} three {4 17} numbersign {4 18} three {4 19} numbersign {4 20} three {4 21} numbersign {4 22} three {4 23} numbersign {4 24} Meta_three {4 25} Meta_numbersign {4 26} Meta_three {4 27} Meta_numbersign {4 28} Meta_three {4 29} Meta_numbersign {4 30} Meta_three {4 31} Meta_numbersign {4 32} three {4 33} numbersign {4 34} three {4 35} numbersign {4 36} three {4 37} numbersign {4 38} three {4 39} numbersign {4 40} Meta_three {4 41} Meta_numbersign {4 42} Meta_three {4 43} Meta_numbersign {4 44} Meta_three {4 45} Meta_numbersign {4 46} Meta_three {4 47} Meta_numbersign {4 48} three {4 49} numbersign {4 50} three {4 51} numbersign {4 52} three {4 53} numbersign {4 54} three {4 55} numbersign {4 56} Meta_three {4 57} Meta_numbersign {4 58} Meta_three {4 59} Meta_numbersign {4 60} Meta_three {4 61} Meta_numbersign {4 62} Meta_three {4 63} Meta_numbersign {4 64} three {4 65} numbersign {4 66} three {4 67} numbersign {4 68} three {4 69} numbersign {4 70} three {4 71} numbersign {4 72} Meta_three {4 73} Meta_numbersign {4 74} Meta_three {4 75} Meta_numbersign {4 76} Meta_three {4 77} Meta_numbersign {4 78} Meta_three {4 79} Meta_numbersign {4 80} three {4 81} numbersign {4 82} three {4 83} numbersign {4 84} three {4 85} numbersign {4 86} three {4 87} numbersign {4 88} Meta_three {4 89} Meta_numbersign {4 90} Meta_three {4 91} Meta_numbersign {4 92} Meta_three {4 93} Meta_numbersign {4 94} Meta_three {4 95} Meta_numbersign {4 96} three {4 97} numbersign {4 98} three {4 99} numbersign {4 100} three {4 101} numbersign {4 102} three {4 103} numbersign {4 104} Meta_three {4 105} Meta_numbersign {4 106} Meta_three {4 107} Meta_numbersign {4 108} Meta_three {4 109} Meta_numbersign {4 110} Meta_three {4 111} Meta_numbersign {4 112} three {4 113} numbersign {4 114} three {4 115} numbersign {4 116} three {4 117} numbersign {4 118} three {4 119} numbersign {4 120} Meta_three {4 121} Meta_numbersign {4 122} Meta_three {4 123} Meta_numbersign {4 124} Meta_three {4 125} Meta_numbersign {4 126} Meta_three {4 127} Meta_numbersign {5 0} four {5 1} dollar {5 2} four {5 3} dollar {5 4} four {5 5} dollar {5 6} four {5 7} dollar {5 8} Meta_four {5 9} Meta_dollar {5 10} Meta_four {5 11} Meta_dollar {5 12} Meta_four {5 13} Meta_dollar {5 14} Meta_four {5 15} Meta_dollar {5 16} four {5 17} dollar {5 18} four {5 19} dollar {5 20} four {5 21} dollar {5 22} four {5 23} dollar {5 24} Meta_four {5 25} Meta_dollar {5 26} Meta_four {5 27} Meta_dollar {5 28} Meta_four {5 29} Meta_dollar {5 30} Meta_four {5 31} Meta_dollar {5 32} four {5 33} dollar {5 34} four {5 35} dollar {5 36} four {5 37} dollar {5 38} four {5 39} dollar {5 40} Meta_four {5 41} Meta_dollar {5 42} Meta_four {5 43} Meta_dollar {5 44} Meta_four {5 45} Meta_dollar {5 46} Meta_four {5 47} Meta_dollar {5 48} four {5 49} dollar {5 50} four {5 51} dollar {5 52} four {5 53} dollar {5 54} four {5 55} dollar {5 56} Meta_four {5 57} Meta_dollar {5 58} Meta_four {5 59} Meta_dollar {5 60} Meta_four {5 61} Meta_dollar {5 62} Meta_four {5 63} Meta_dollar {5 64} four {5 65} dollar {5 66} four {5 67} dollar {5 68} four {5 69} dollar {5 70} four {5 71} dollar {5 72} Meta_four {5 73} Meta_dollar {5 74} Meta_four {5 75} Meta_dollar {5 76} Meta_four {5 77} Meta_dollar {5 78} Meta_four {5 79} Meta_dollar {5 80} four {5 81} dollar {5 82} four {5 83} dollar {5 84} four {5 85} dollar {5 86} four {5 87} dollar {5 88} Meta_four {5 89} Meta_dollar {5 90} Meta_four {5 91} Meta_dollar {5 92} Meta_four {5 93} Meta_dollar {5 94} Meta_four {5 95} Meta_dollar {5 96} four {5 97} dollar {5 98} four {5 99} dollar {5 100} four {5 101} dollar {5 102} four {5 103} dollar {5 104} Meta_four {5 105} Meta_dollar {5 106} Meta_four {5 107} Meta_dollar {5 108} Meta_four {5 109} Meta_dollar {5 110} Meta_four {5 111} Meta_dollar {5 112} four {5 113} dollar {5 114} four {5 115} dollar {5 116} four {5 117} dollar {5 118} four {5 119} dollar {5 120} Meta_four {5 121} Meta_dollar {5 122} Meta_four {5 123} Meta_dollar {5 124} Meta_four {5 125} Meta_dollar {5 126} Meta_four {5 127} Meta_dollar {6 0} five {6 1} percent {6 2} five {6 3} percent {6 4} five {6 5} percent {6 6} five {6 7} percent {6 8} Meta_five {6 9} Meta_percent {6 10} Meta_five {6 11} Meta_percent {6 12} Meta_five {6 13} Meta_percent {6 14} Meta_five {6 15} Meta_percent {6 16} five {6 17} percent {6 18} five {6 19} percent {6 20} five {6 21} percent {6 22} five {6 23} percent {6 24} Meta_five {6 25} Meta_percent {6 26} Meta_five {6 27} Meta_percent {6 28} Meta_five {6 29} Meta_percent {6 30} Meta_five {6 31} Meta_percent {6 32} five {6 33} percent {6 34} five {6 35} percent {6 36} five {6 37} percent {6 38} five {6 39} percent {6 40} Meta_five {6 41} Meta_percent {6 42} Meta_five {6 43} Meta_percent {6 44} Meta_five {6 45} Meta_percent {6 46} Meta_five {6 47} Meta_percent {6 48} five {6 49} percent {6 50} five {6 51} percent {6 52} five {6 53} percent {6 54} five {6 55} percent {6 56} Meta_five {6 57} Meta_percent {6 58} Meta_five {6 59} Meta_percent {6 60} Meta_five {6 61} Meta_percent {6 62} Meta_five {6 63} Meta_percent {6 64} five {6 65} percent {6 66} five {6 67} percent {6 68} five {6 69} percent {6 70} five {6 71} percent {6 72} Meta_five {6 73} Meta_percent {6 74} Meta_five {6 75} Meta_percent {6 76} Meta_five {6 77} Meta_percent {6 78} Meta_five {6 79} Meta_percent {6 80} five {6 81} percent {6 82} five {6 83} percent {6 84} five {6 85} percent {6 86} five {6 87} percent {6 88} Meta_five {6 89} Meta_percent {6 90} Meta_five {6 91} Meta_percent {6 92} Meta_five {6 93} Meta_percent {6 94} Meta_five {6 95} Meta_percent {6 96} five {6 97} percent {6 98} five {6 99} percent {6 100} five {6 101} percent {6 102} five {6 103} percent {6 104} Meta_five {6 105} Meta_percent {6 106} Meta_five {6 107} Meta_percent {6 108} Meta_five {6 109} Meta_percent {6 110} Meta_five {6 111} Meta_percent {6 112} five {6 113} percent {6 114} five {6 115} percent {6 116} five {6 117} percent {6 118} five {6 119} percent {6 120} Meta_five {6 121} Meta_percent {6 122} Meta_five {6 123} Meta_percent {6 124} Meta_five {6 125} Meta_percent {6 126} Meta_five {6 127} Meta_percent {7 0} six {7 1} asciicircum {7 2} six {7 3} asciicircum {7 4} Control_asciicircum {7 5} Control_asciicircum {7 6} Control_asciicircum {7 7} Control_asciicircum {7 8} Meta_six {7 9} Meta_asciicircum {7 10} Meta_six {7 11} Meta_asciicircum {7 12} Meta_Control_asciicircum {7 13} Meta_Control_asciicircum {7 14} Meta_Control_asciicircum {7 15} Meta_Control_asciicircum {7 16} six {7 17} asciicircum {7 18} six {7 19} asciicircum {7 20} Control_asciicircum {7 21} Control_asciicircum {7 22} Control_asciicircum {7 23} Control_asciicircum {7 24} Meta_six {7 25} Meta_asciicircum {7 26} Meta_six {7 27} Meta_asciicircum {7 28} Meta_Control_asciicircum {7 29} Meta_Control_asciicircum {7 30} Meta_Control_asciicircum {7 31} Meta_Control_asciicircum {7 32} six {7 33} asciicircum {7 34} six {7 35} asciicircum {7 36} Control_asciicircum {7 37} Control_asciicircum {7 38} Control_asciicircum {7 39} Control_asciicircum {7 40} Meta_six {7 41} Meta_asciicircum {7 42} Meta_six {7 43} Meta_asciicircum {7 44} Meta_Control_asciicircum {7 45} Meta_Control_asciicircum {7 46} Meta_Control_asciicircum {7 47} Meta_Control_asciicircum {7 48} six {7 49} asciicircum {7 50} six {7 51} asciicircum {7 52} Control_asciicircum {7 53} Control_asciicircum {7 54} Control_asciicircum {7 55} Control_asciicircum {7 56} Meta_six {7 57} Meta_asciicircum {7 58} Meta_six {7 59} Meta_asciicircum {7 60} Meta_Control_asciicircum {7 61} Meta_Control_asciicircum {7 62} Meta_Control_asciicircum {7 63} Meta_Control_asciicircum {7 64} six {7 65} asciicircum {7 66} six {7 67} asciicircum {7 68} Control_asciicircum {7 69} Control_asciicircum {7 70} Control_asciicircum {7 71} Control_asciicircum {7 72} Meta_six {7 73} Meta_asciicircum {7 74} Meta_six {7 75} Meta_asciicircum {7 76} Meta_Control_asciicircum {7 77} Meta_Control_asciicircum {7 78} Meta_Control_asciicircum {7 79} Meta_Control_asciicircum {7 80} six {7 81} asciicircum {7 82} six {7 83} asciicircum {7 84} Control_asciicircum {7 85} Control_asciicircum {7 86} Control_asciicircum {7 87} Control_asciicircum {7 88} Meta_six {7 89} Meta_asciicircum {7 90} Meta_six {7 91} Meta_asciicircum {7 92} Meta_Control_asciicircum {7 93} Meta_Control_asciicircum {7 94} Meta_Control_asciicircum {7 95} Meta_Control_asciicircum {7 96} six {7 97} asciicircum {7 98} six {7 99} asciicircum {7 100} Control_asciicircum {7 101} Control_asciicircum {7 102} Control_asciicircum {7 103} Control_asciicircum {7 104} Meta_six {7 105} Meta_asciicircum {7 106} Meta_six {7 107} Meta_asciicircum {7 108} Meta_Control_asciicircum {7 109} Meta_Control_asciicircum {7 110} Meta_Control_asciicircum {7 111} Meta_Control_asciicircum {7 112} six {7 113} asciicircum {7 114} six {7 115} asciicircum {7 116} Control_asciicircum {7 117} Control_asciicircum {7 118} Control_asciicircum {7 119} Control_asciicircum {7 120} Meta_six {7 121} Meta_asciicircum {7 122} Meta_six {7 123} Meta_asciicircum {7 124} Meta_Control_asciicircum {7 125} Meta_Control_asciicircum {7 126} Meta_Control_asciicircum {7 127} Meta_Control_asciicircum {8 0} seven {8 1} ampersand {8 2} seven {8 3} ampersand {8 4} seven {8 5} ampersand {8 6} seven {8 7} ampersand {8 8} Meta_seven {8 9} Meta_ampersand {8 10} Meta_seven {8 11} Meta_ampersand {8 12} Meta_seven {8 13} Meta_ampersand {8 14} Meta_seven {8 15} Meta_ampersand {8 16} seven {8 17} ampersand {8 18} seven {8 19} ampersand {8 20} seven {8 21} ampersand {8 22} seven {8 23} ampersand {8 24} Meta_seven {8 25} Meta_ampersand {8 26} Meta_seven {8 27} Meta_ampersand {8 28} Meta_seven {8 29} Meta_ampersand {8 30} Meta_seven {8 31} Meta_ampersand {8 32} seven {8 33} ampersand {8 34} seven {8 35} ampersand {8 36} seven {8 37} ampersand {8 38} seven {8 39} ampersand {8 40} Meta_seven {8 41} Meta_ampersand {8 42} Meta_seven {8 43} Meta_ampersand {8 44} Meta_seven {8 45} Meta_ampersand {8 46} Meta_seven {8 47} Meta_ampersand {8 48} seven {8 49} ampersand {8 50} seven {8 51} ampersand {8 52} seven {8 53} ampersand {8 54} seven {8 55} ampersand {8 56} Meta_seven {8 57} Meta_ampersand {8 58} Meta_seven {8 59} Meta_ampersand {8 60} Meta_seven {8 61} Meta_ampersand {8 62} Meta_seven {8 63} Meta_ampersand {8 64} seven {8 65} ampersand {8 66} seven {8 67} ampersand {8 68} seven {8 69} ampersand {8 70} seven {8 71} ampersand {8 72} Meta_seven {8 73} Meta_ampersand {8 74} Meta_seven {8 75} Meta_ampersand {8 76} Meta_seven {8 77} Meta_ampersand {8 78} Meta_seven {8 79} Meta_ampersand {8 80} seven {8 81} ampersand {8 82} seven {8 83} ampersand {8 84} seven {8 85} ampersand {8 86} seven {8 87} ampersand {8 88} Meta_seven {8 89} Meta_ampersand {8 90} Meta_seven {8 91} Meta_ampersand {8 92} Meta_seven {8 93} Meta_ampersand {8 94} Meta_seven {8 95} Meta_ampersand {8 96} seven {8 97} ampersand {8 98} seven {8 99} ampersand {8 100} seven {8 101} ampersand {8 102} seven {8 103} ampersand {8 104} Meta_seven {8 105} Meta_ampersand {8 106} Meta_seven {8 107} Meta_ampersand {8 108} Meta_seven {8 109} Meta_ampersand {8 110} Meta_seven {8 111} Meta_ampersand {8 112} seven {8 113} ampersand {8 114} seven {8 115} ampersand {8 116} seven {8 117} ampersand {8 118} seven {8 119} ampersand {8 120} Meta_seven {8 121} Meta_ampersand {8 122} Meta_seven {8 123} Meta_ampersand {8 124} Meta_seven {8 125} Meta_ampersand {8 126} Meta_seven {8 127} Meta_ampersand {9 0} eight {9 1} asterisk {9 2} eight {9 3} asterisk {9 4} eight {9 5} asterisk {9 6} eight {9 7} asterisk {9 8} Meta_eight {9 9} Meta_asterisk {9 10} Meta_eight {9 11} Meta_asterisk {9 12} Meta_eight {9 13} Meta_asterisk {9 14} Meta_eight {9 15} Meta_asterisk {9 16} eight {9 17} asterisk {9 18} eight {9 19} asterisk {9 20} eight {9 21} asterisk {9 22} eight {9 23} asterisk {9 24} Meta_eight {9 25} Meta_asterisk {9 26} Meta_eight {9 27} Meta_asterisk {9 28} Meta_eight {9 29} Meta_asterisk {9 30} Meta_eight {9 31} Meta_asterisk {9 32} eight {9 33} asterisk {9 34} eight {9 35} asterisk {9 36} eight {9 37} asterisk {9 38} eight {9 39} asterisk {9 40} Meta_eight {9 41} Meta_asterisk {9 42} Meta_eight {9 43} Meta_asterisk {9 44} Meta_eight {9 45} Meta_asterisk {9 46} Meta_eight {9 47} Meta_asterisk {9 48} eight {9 49} asterisk {9 50} eight {9 51} asterisk {9 52} eight {9 53} asterisk {9 54} eight {9 55} asterisk {9 56} Meta_eight {9 57} Meta_asterisk {9 58} Meta_eight {9 59} Meta_asterisk {9 60} Meta_eight {9 61} Meta_asterisk {9 62} Meta_eight {9 63} Meta_asterisk {9 64} eight {9 65} asterisk {9 66} eight {9 67} asterisk {9 68} eight {9 69} asterisk {9 70} eight {9 71} asterisk {9 72} Meta_eight {9 73} Meta_asterisk {9 74} Meta_eight {9 75} Meta_asterisk {9 76} Meta_eight {9 77} Meta_asterisk {9 78} Meta_eight {9 79} Meta_asterisk {9 80} eight {9 81} asterisk {9 82} eight {9 83} asterisk {9 84} eight {9 85} asterisk {9 86} eight {9 87} asterisk {9 88} Meta_eight {9 89} Meta_asterisk {9 90} Meta_eight {9 91} Meta_asterisk {9 92} Meta_eight {9 93} Meta_asterisk {9 94} Meta_eight {9 95} Meta_asterisk {9 96} eight {9 97} asterisk {9 98} eight {9 99} asterisk {9 100} eight {9 101} asterisk {9 102} eight {9 103} asterisk {9 104} Meta_eight {9 105} Meta_asterisk {9 106} Meta_eight {9 107} Meta_asterisk {9 108} Meta_eight {9 109} Meta_asterisk {9 110} Meta_eight {9 111} Meta_asterisk {9 112} eight {9 113} asterisk {9 114} eight {9 115} asterisk {9 116} eight {9 117} asterisk {9 118} eight {9 119} asterisk {9 120} Meta_eight {9 121} Meta_asterisk {9 122} Meta_eight {9 123} Meta_asterisk {9 124} Meta_eight {9 125} Meta_asterisk {9 126} Meta_eight {9 127} Meta_asterisk {10 0} nine {10 1} parenleft {10 2} nine {10 3} parenleft {10 4} nine {10 5} parenleft {10 6} nine {10 7} parenleft {10 8} Meta_nine {10 9} Meta_parenleft {10 10} Meta_nine {10 11} Meta_parenleft {10 12} Meta_nine {10 13} Meta_parenleft {10 14} Meta_nine {10 15} Meta_parenleft {10 16} nine {10 17} parenleft {10 18} nine {10 19} parenleft {10 20} nine {10 21} parenleft {10 22} nine {10 23} parenleft {10 24} Meta_nine {10 25} Meta_parenleft {10 26} Meta_nine {10 27} Meta_parenleft {10 28} Meta_nine {10 29} Meta_parenleft {10 30} Meta_nine {10 31} Meta_parenleft {10 32} nine {10 33} parenleft {10 34} nine {10 35} parenleft {10 36} nine {10 37} parenleft {10 38} nine {10 39} parenleft {10 40} Meta_nine {10 41} Meta_parenleft {10 42} Meta_nine {10 43} Meta_parenleft {10 44} Meta_nine {10 45} Meta_parenleft {10 46} Meta_nine {10 47} Meta_parenleft {10 48} nine {10 49} parenleft {10 50} nine {10 51} parenleft {10 52} nine {10 53} parenleft {10 54} nine {10 55} parenleft {10 56} Meta_nine {10 57} Meta_parenleft {10 58} Meta_nine {10 59} Meta_parenleft {10 60} Meta_nine {10 61} Meta_parenleft {10 62} Meta_nine {10 63} Meta_parenleft {10 64} nine {10 65} parenleft {10 66} nine {10 67} parenleft {10 68} nine {10 69} parenleft {10 70} nine {10 71} parenleft {10 72} Meta_nine {10 73} Meta_parenleft {10 74} Meta_nine {10 75} Meta_parenleft {10 76} Meta_nine {10 77} Meta_parenleft {10 78} Meta_nine {10 79} Meta_parenleft {10 80} nine {10 81} parenleft {10 82} nine {10 83} parenleft {10 84} nine {10 85} parenleft {10 86} nine {10 87} parenleft {10 88} Meta_nine {10 89} Meta_parenleft {10 90} Meta_nine {10 91} Meta_parenleft {10 92} Meta_nine {10 93} Meta_parenleft {10 94} Meta_nine {10 95} Meta_parenleft {10 96} nine {10 97} parenleft {10 98} nine {10 99} parenleft {10 100} nine {10 101} parenleft {10 102} nine {10 103} parenleft {10 104} Meta_nine {10 105} Meta_parenleft {10 106} Meta_nine {10 107} Meta_parenleft {10 108} Meta_nine {10 109} Meta_parenleft {10 110} Meta_nine {10 111} Meta_parenleft {10 112} nine {10 113} parenleft {10 114} nine {10 115} parenleft {10 116} nine {10 117} parenleft {10 118} nine {10 119} parenleft {10 120} Meta_nine {10 121} Meta_parenleft {10 122} Meta_nine {10 123} Meta_parenleft {10 124} Meta_nine {10 125} Meta_parenleft {10 126} Meta_nine {10 127} Meta_parenleft {11 0} zero {11 1} parenright {11 2} zero {11 3} parenright {11 4} zero {11 5} parenright {11 6} zero {11 7} parenright {11 8} Meta_zero {11 9} Meta_parenright {11 10} Meta_zero {11 11} Meta_parenright {11 12} Meta_zero {11 13} Meta_parenright {11 14} Meta_zero {11 15} Meta_parenright {11 16} zero {11 17} parenright {11 18} zero {11 19} parenright {11 20} zero {11 21} parenright {11 22} zero {11 23} parenright {11 24} Meta_zero {11 25} Meta_parenright {11 26} Meta_zero {11 27} Meta_parenright {11 28} Meta_zero {11 29} Meta_parenright {11 30} Meta_zero {11 31} Meta_parenright {11 32} zero {11 33} parenright {11 34} zero {11 35} parenright {11 36} zero {11 37} parenright {11 38} zero {11 39} parenright {11 40} Meta_zero {11 41} Meta_parenright {11 42} Meta_zero {11 43} Meta_parenright {11 44} Meta_zero {11 45} Meta_parenright {11 46} Meta_zero {11 47} Meta_parenright {11 48} zero {11 49} parenright {11 50} zero {11 51} parenright {11 52} zero {11 53} parenright {11 54} zero {11 55} parenright {11 56} Meta_zero {11 57} Meta_parenright {11 58} Meta_zero {11 59} Meta_parenright {11 60} Meta_zero {11 61} Meta_parenright {11 62} Meta_zero {11 63} Meta_parenright {11 64} zero {11 65} parenright {11 66} zero {11 67} parenright {11 68} zero {11 69} parenright {11 70} zero {11 71} parenright {11 72} Meta_zero {11 73} Meta_parenright {11 74} Meta_zero {11 75} Meta_parenright {11 76} Meta_zero {11 77} Meta_parenright {11 78} Meta_zero {11 79} Meta_parenright {11 80} zero {11 81} parenright {11 82} zero {11 83} parenright {11 84} zero {11 85} parenright {11 86} zero {11 87} parenright {11 88} Meta_zero {11 89} Meta_parenright {11 90} Meta_zero {11 91} Meta_parenright {11 92} Meta_zero {11 93} Meta_parenright {11 94} Meta_zero {11 95} Meta_parenright {11 96} zero {11 97} parenright {11 98} zero {11 99} parenright {11 100} zero {11 101} parenright {11 102} zero {11 103} parenright {11 104} Meta_zero {11 105} Meta_parenright {11 106} Meta_zero {11 107} Meta_parenright {11 108} Meta_zero {11 109} Meta_parenright {11 110} Meta_zero {11 111} Meta_parenright {11 112} zero {11 113} parenright {11 114} zero {11 115} parenright {11 116} zero {11 117} parenright {11 118} zero {11 119} parenright {11 120} Meta_zero {11 121} Meta_parenright {11 122} Meta_zero {11 123} Meta_parenright {11 124} Meta_zero {11 125} Meta_parenright {11 126} Meta_zero {11 127} Meta_parenright {12 0} minus {12 1} underscore {12 2} minus {12 3} underscore {12 4} Control_underscore {12 5} Control_underscore {12 6} Control_underscore {12 7} Control_underscore {12 8} Meta_minus {12 9} Meta_underscore {12 10} Meta_minus {12 11} Meta_underscore {12 12} Meta_Control_underscore {12 13} Meta_Control_underscore {12 14} Meta_Control_underscore {12 15} Meta_Control_underscore {12 16} minus {12 17} underscore {12 18} minus {12 19} underscore {12 20} Control_underscore {12 21} Control_underscore {12 22} Control_underscore {12 23} Control_underscore {12 24} Meta_minus {12 25} Meta_underscore {12 26} Meta_minus {12 27} Meta_underscore {12 28} Meta_Control_underscore {12 29} Meta_Control_underscore {12 30} Meta_Control_underscore {12 31} Meta_Control_underscore {12 32} minus {12 33} underscore {12 34} minus {12 35} underscore {12 36} Control_underscore {12 37} Control_underscore {12 38} Control_underscore {12 39} Control_underscore {12 40} Meta_minus {12 41} Meta_underscore {12 42} Meta_minus {12 43} Meta_underscore {12 44} Meta_Control_underscore {12 45} Meta_Control_underscore {12 46} Meta_Control_underscore {12 47} Meta_Control_underscore {12 48} minus {12 49} underscore {12 50} minus {12 51} underscore {12 52} Control_underscore {12 53} Control_underscore {12 54} Control_underscore {12 55} Control_underscore {12 56} Meta_minus {12 57} Meta_underscore {12 58} Meta_minus {12 59} Meta_underscore {12 60} Meta_Control_underscore {12 61} Meta_Control_underscore {12 62} Meta_Control_underscore {12 63} Meta_Control_underscore {12 64} minus {12 65} underscore {12 66} minus {12 67} underscore {12 68} Control_underscore {12 69} Control_underscore {12 70} Control_underscore {12 71} Control_underscore {12 72} Meta_minus {12 73} Meta_underscore {12 74} Meta_minus {12 75} Meta_underscore {12 76} Meta_Control_underscore {12 77} Meta_Control_underscore {12 78} Meta_Control_underscore {12 79} Meta_Control_underscore {12 80} minus {12 81} underscore {12 82} minus {12 83} underscore {12 84} Control_underscore {12 85} Control_underscore {12 86} Control_underscore {12 87} Control_underscore {12 88} Meta_minus {12 89} Meta_underscore {12 90} Meta_minus {12 91} Meta_underscore {12 92} Meta_Control_underscore {12 93} Meta_Control_underscore {12 94} Meta_Control_underscore {12 95} Meta_Control_underscore {12 96} minus {12 97} underscore {12 98} minus {12 99} underscore {12 100} Control_underscore {12 101} Control_underscore {12 102} Control_underscore {12 103} Control_underscore {12 104} Meta_minus {12 105} Meta_underscore {12 106} Meta_minus {12 107} Meta_underscore {12 108} Meta_Control_underscore {12 109} Meta_Control_underscore {12 110} Meta_Control_underscore {12 111} Meta_Control_underscore {12 112} minus {12 113} underscore {12 114} minus {12 115} underscore {12 116} Control_underscore {12 117} Control_underscore {12 118} Control_underscore {12 119} Control_underscore {12 120} Meta_minus {12 121} Meta_underscore {12 122} Meta_minus {12 123} Meta_underscore {12 124} Meta_Control_underscore {12 125} Meta_Control_underscore {12 126} Meta_Control_underscore {12 127} Meta_Control_underscore {13 0} equal {13 1} plus {13 2} equal {13 3} plus {13 4} equal {13 5} plus {13 6} equal {13 7} plus {13 8} Meta_equal {13 9} Meta_plus {13 10} Meta_equal {13 11} Meta_plus {13 12} Meta_equal {13 13} Meta_plus {13 14} Meta_equal {13 15} Meta_plus {13 16} equal {13 17} plus {13 18} equal {13 19} plus {13 20} equal {13 21} plus {13 22} equal {13 23} plus {13 24} Meta_equal {13 25} Meta_plus {13 26} Meta_equal {13 27} Meta_plus {13 28} Meta_equal {13 29} Meta_plus {13 30} Meta_equal {13 31} Meta_plus {13 32} equal {13 33} plus {13 34} equal {13 35} plus {13 36} equal {13 37} plus {13 38} equal {13 39} plus {13 40} Meta_equal {13 41} Meta_plus {13 42} Meta_equal {13 43} Meta_plus {13 44} Meta_equal {13 45} Meta_plus {13 46} Meta_equal {13 47} Meta_plus {13 48} equal {13 49} plus {13 50} equal {13 51} plus {13 52} equal {13 53} plus {13 54} equal {13 55} plus {13 56} Meta_equal {13 57} Meta_plus {13 58} Meta_equal {13 59} Meta_plus {13 60} Meta_equal {13 61} Meta_plus {13 62} Meta_equal {13 63} Meta_plus {13 64} equal {13 65} plus {13 66} equal {13 67} plus {13 68} equal {13 69} plus {13 70} equal {13 71} plus {13 72} Meta_equal {13 73} Meta_plus {13 74} Meta_equal {13 75} Meta_plus {13 76} Meta_equal {13 77} Meta_plus {13 78} Meta_equal {13 79} Meta_plus {13 80} equal {13 81} plus {13 82} equal {13 83} plus {13 84} equal {13 85} plus {13 86} equal {13 87} plus {13 88} Meta_equal {13 89} Meta_plus {13 90} Meta_equal {13 91} Meta_plus {13 92} Meta_equal {13 93} Meta_plus {13 94} Meta_equal {13 95} Meta_plus {13 96} equal {13 97} plus {13 98} equal {13 99} plus {13 100} equal {13 101} plus {13 102} equal {13 103} plus {13 104} Meta_equal {13 105} Meta_plus {13 106} Meta_equal {13 107} Meta_plus {13 108} Meta_equal {13 109} Meta_plus {13 110} Meta_equal {13 111} Meta_plus {13 112} equal {13 113} plus {13 114} equal {13 115} plus {13 116} equal {13 117} plus {13 118} equal {13 119} plus {13 120} Meta_equal {13 121} Meta_plus {13 122} Meta_equal {13 123} Meta_plus {13 124} Meta_equal {13 125} Meta_plus {13 126} Meta_equal {13 127} Meta_plus {14 0} Delete {14 1} Delete {14 2} Delete {14 3} Delete {14 4} BackSpace {14 5} BackSpace {14 6} BackSpace {14 7} BackSpace {14 8} Meta_Delete {14 9} Meta_Delete {14 10} Meta_Delete {14 11} Meta_Delete {14 12} Meta_BackSpace {14 13} Meta_BackSpace {14 14} Meta_BackSpace {14 15} Meta_BackSpace {14 16} Delete {14 17} Delete {14 18} Delete {14 19} Delete {14 20} BackSpace {14 21} BackSpace {14 22} BackSpace {14 23} BackSpace {14 24} Meta_Delete {14 25} Meta_Delete {14 26} Meta_Delete {14 27} Meta_Delete {14 28} Meta_BackSpace {14 29} Meta_BackSpace {14 30} Meta_BackSpace {14 31} Meta_BackSpace {14 32} Delete {14 33} Delete {14 34} Delete {14 35} Delete {14 36} BackSpace {14 37} BackSpace {14 38} BackSpace {14 39} BackSpace {14 40} Meta_Delete {14 41} Meta_Delete {14 42} Meta_Delete {14 43} Meta_Delete {14 44} Meta_BackSpace {14 45} Meta_BackSpace {14 46} Meta_BackSpace {14 47} Meta_BackSpace {14 48} Delete {14 49} Delete {14 50} Delete {14 51} Delete {14 52} BackSpace {14 53} BackSpace {14 54} BackSpace {14 55} BackSpace {14 56} Meta_Delete {14 57} Meta_Delete {14 58} Meta_Delete {14 59} Meta_Delete {14 60} Meta_BackSpace {14 61} Meta_BackSpace {14 62} Meta_BackSpace {14 63} Meta_BackSpace {14 64} Delete {14 65} Delete {14 66} Delete {14 67} Delete {14 68} BackSpace {14 69} BackSpace {14 70} BackSpace {14 71} BackSpace {14 72} Meta_Delete {14 73} Meta_Delete {14 74} Meta_Delete {14 75} Meta_Delete {14 76} Meta_BackSpace {14 77} Meta_BackSpace {14 78} Meta_BackSpace {14 79} Meta_BackSpace {14 80} Delete {14 81} Delete {14 82} Delete {14 83} Delete {14 84} BackSpace {14 85} BackSpace {14 86} BackSpace {14 87} BackSpace {14 88} Meta_Delete {14 89} Meta_Delete {14 90} Meta_Delete {14 91} Meta_Delete {14 92} Meta_BackSpace {14 93} Meta_BackSpace {14 94} Meta_BackSpace {14 95} Meta_BackSpace {14 96} Delete {14 97} Delete {14 98} Delete {14 99} Delete {14 100} BackSpace {14 101} BackSpace {14 102} BackSpace {14 103} BackSpace {14 104} Meta_Delete {14 105} Meta_Delete {14 106} Meta_Delete {14 107} Meta_Delete {14 108} Meta_BackSpace {14 109} Meta_BackSpace {14 110} Meta_BackSpace {14 111} Meta_BackSpace {14 112} Delete {14 113} Delete {14 114} Delete {14 115} Delete {14 116} BackSpace {14 117} BackSpace {14 118} BackSpace {14 119} BackSpace {14 120} Meta_Delete {14 121} Meta_Delete {14 122} Meta_Delete {14 123} Meta_Delete {14 124} Meta_BackSpace {14 125} Meta_BackSpace {14 126} Meta_BackSpace {14 127} Meta_BackSpace {15 0} Tab {15 1} Meta_Tab {15 2} Tab {15 3} Meta_Tab {15 4} Tab {15 5} Tab {15 6} Tab {15 7} Tab {15 8} Meta_Tab {15 9} Meta_Tab {15 10} Meta_Tab {15 11} Meta_Tab {15 12} Meta_Tab {15 13} Meta_Tab {15 14} Meta_Tab {15 15} Meta_Tab {15 16} Tab {15 17} Meta_Tab {15 18} Tab {15 19} Meta_Tab {15 20} Tab {15 21} Tab {15 22} Tab {15 23} Tab {15 24} Meta_Tab {15 25} Meta_Tab {15 26} Meta_Tab {15 27} Meta_Tab {15 28} Meta_Tab {15 29} Meta_Tab {15 30} Meta_Tab {15 31} Meta_Tab {15 32} Tab {15 33} Meta_Tab {15 34} Tab {15 35} Meta_Tab {15 36} Tab {15 37} Tab {15 38} Tab {15 39} Tab {15 40} Meta_Tab {15 41} Meta_Tab {15 42} Meta_Tab {15 43} Meta_Tab {15 44} Meta_Tab {15 45} Meta_Tab {15 46} Meta_Tab {15 47} Meta_Tab {15 48} Tab {15 49} Meta_Tab {15 50} Tab {15 51} Meta_Tab {15 52} Tab {15 53} Tab {15 54} Tab {15 55} Tab {15 56} Meta_Tab {15 57} Meta_Tab {15 58} Meta_Tab {15 59} Meta_Tab {15 60} Meta_Tab {15 61} Meta_Tab {15 62} Meta_Tab {15 63} Meta_Tab {15 64} Tab {15 65} Meta_Tab {15 66} Tab {15 67} Meta_Tab {15 68} Tab {15 69} Tab {15 70} Tab {15 71} Tab {15 72} Meta_Tab {15 73} Meta_Tab {15 74} Meta_Tab {15 75} Meta_Tab {15 76} Meta_Tab {15 77} Meta_Tab {15 78} Meta_Tab {15 79} Meta_Tab {15 80} Tab {15 81} Meta_Tab {15 82} Tab {15 83} Meta_Tab {15 84} Tab {15 85} Tab {15 86} Tab {15 87} Tab {15 88} Meta_Tab {15 89} Meta_Tab {15 90} Meta_Tab {15 91} Meta_Tab {15 92} Meta_Tab {15 93} Meta_Tab {15 94} Meta_Tab {15 95} Meta_Tab {15 96} Tab {15 97} Meta_Tab {15 98} Tab {15 99} Meta_Tab {15 100} Tab {15 101} Tab {15 102} Tab {15 103} Tab {15 104} Meta_Tab {15 105} Meta_Tab {15 106} Meta_Tab {15 107} Meta_Tab {15 108} Meta_Tab {15 109} Meta_Tab {15 110} Meta_Tab {15 111} Meta_Tab {15 112} Tab {15 113} Meta_Tab {15 114} Tab {15 115} Meta_Tab {15 116} Tab {15 117} Tab {15 118} Tab {15 119} Tab {15 120} Meta_Tab {15 121} Meta_Tab {15 122} Meta_Tab {15 123} Meta_Tab {15 124} Meta_Tab {15 125} Meta_Tab {15 126} Meta_Tab {15 127} Meta_Tab {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} Control_q {16 5} Control_q {16 6} Control_q {16 7} Control_q {16 8} Meta_q {16 9} Meta_Q {16 10} Meta_q {16 11} Meta_Q {16 12} Meta_Control_q {16 13} Meta_Control_q {16 14} Meta_Control_q {16 15} Meta_Control_q {16 16} q {16 17} Q {16 18} q {16 19} Q {16 20} Control_q {16 21} Control_q {16 22} Control_q {16 23} Control_q {16 24} Meta_q {16 25} Meta_Q {16 26} Meta_q {16 27} Meta_Q {16 28} Meta_Control_q {16 29} Meta_Control_q {16 30} Meta_Control_q {16 31} Meta_Control_q {16 32} q {16 33} Q {16 34} q {16 35} Q {16 36} Control_q {16 37} Control_q {16 38} Control_q {16 39} Control_q {16 40} Meta_q {16 41} Meta_Q {16 42} Meta_q {16 43} Meta_Q {16 44} Meta_Control_q {16 45} Meta_Control_q {16 46} Meta_Control_q {16 47} Meta_Control_q {16 48} q {16 49} Q {16 50} q {16 51} Q {16 52} Control_q {16 53} Control_q {16 54} Control_q {16 55} Control_q {16 56} Meta_q {16 57} Meta_Q {16 58} Meta_q {16 59} Meta_Q {16 60} Meta_Control_q {16 61} Meta_Control_q {16 62} Meta_Control_q {16 63} Meta_Control_q {16 64} Q {16 65} q {16 66} Q {16 67} q {16 68} Control_q {16 69} Control_q {16 70} Control_q {16 71} Control_q {16 72} Meta_q {16 73} Meta_Q {16 74} Meta_q {16 75} Meta_Q {16 76} Meta_Control_q {16 77} Meta_Control_q {16 78} Meta_Control_q {16 79} Meta_Control_q {16 80} Q {16 81} q {16 82} Q {16 83} q {16 84} Control_q {16 85} Control_q {16 86} Control_q {16 87} Control_q {16 88} Meta_q {16 89} Meta_Q {16 90} Meta_q {16 91} Meta_Q {16 92} Meta_Control_q {16 93} Meta_Control_q {16 94} Meta_Control_q {16 95} Meta_Control_q {16 96} Q {16 97} q {16 98} Q {16 99} q {16 100} Control_q {16 101} Control_q {16 102} Control_q {16 103} Control_q {16 104} Meta_q {16 105} Meta_Q {16 106} Meta_q {16 107} Meta_Q {16 108} Meta_Control_q {16 109} Meta_Control_q {16 110} Meta_Control_q {16 111} Meta_Control_q {16 112} Q {16 113} q {16 114} Q {16 115} q {16 116} Control_q {16 117} Control_q {16 118} Control_q {16 119} Control_q {16 120} Meta_q {16 121} Meta_Q {16 122} Meta_q {16 123} Meta_Q {16 124} Meta_Control_q {16 125} Meta_Control_q {16 126} Meta_Control_q {16 127} Meta_Control_q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} Control_w {17 5} Control_w {17 6} Control_w {17 7} Control_w {17 8} Meta_w {17 9} Meta_W {17 10} Meta_w {17 11} Meta_W {17 12} Meta_Control_w {17 13} Meta_Control_w {17 14} Meta_Control_w {17 15} Meta_Control_w {17 16} w {17 17} W {17 18} w {17 19} W {17 20} Control_w {17 21} Control_w {17 22} Control_w {17 23} Control_w {17 24} Meta_w {17 25} Meta_W {17 26} Meta_w {17 27} Meta_W {17 28} Meta_Control_w {17 29} Meta_Control_w {17 30} Meta_Control_w {17 31} Meta_Control_w {17 32} w {17 33} W {17 34} w {17 35} W {17 36} Control_w {17 37} Control_w {17 38} Control_w {17 39} Control_w {17 40} Meta_w {17 41} Meta_W {17 42} Meta_w {17 43} Meta_W {17 44} Meta_Control_w {17 45} Meta_Control_w {17 46} Meta_Control_w {17 47} Meta_Control_w {17 48} w {17 49} W {17 50} w {17 51} W {17 52} Control_w {17 53} Control_w {17 54} Control_w {17 55} Control_w {17 56} Meta_w {17 57} Meta_W {17 58} Meta_w {17 59} Meta_W {17 60} Meta_Control_w {17 61} Meta_Control_w {17 62} Meta_Control_w {17 63} Meta_Control_w {17 64} W {17 65} w {17 66} W {17 67} w {17 68} Control_w {17 69} Control_w {17 70} Control_w {17 71} Control_w {17 72} Meta_w {17 73} Meta_W {17 74} Meta_w {17 75} Meta_W {17 76} Meta_Control_w {17 77} Meta_Control_w {17 78} Meta_Control_w {17 79} Meta_Control_w {17 80} W {17 81} w {17 82} W {17 83} w {17 84} Control_w {17 85} Control_w {17 86} Control_w {17 87} Control_w {17 88} Meta_w {17 89} Meta_W {17 90} Meta_w {17 91} Meta_W {17 92} Meta_Control_w {17 93} Meta_Control_w {17 94} Meta_Control_w {17 95} Meta_Control_w {17 96} W {17 97} w {17 98} W {17 99} w {17 100} Control_w {17 101} Control_w {17 102} Control_w {17 103} Control_w {17 104} Meta_w {17 105} Meta_W {17 106} Meta_w {17 107} Meta_W {17 108} Meta_Control_w {17 109} Meta_Control_w {17 110} Meta_Control_w {17 111} Meta_Control_w {17 112} W {17 113} w {17 114} W {17 115} w {17 116} Control_w {17 117} Control_w {17 118} Control_w {17 119} Control_w {17 120} Meta_w {17 121} Meta_W {17 122} Meta_w {17 123} Meta_W {17 124} Meta_Control_w {17 125} Meta_Control_w {17 126} Meta_Control_w {17 127} Meta_Control_w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} Control_e {18 5} Control_e {18 6} Control_e {18 7} Control_e {18 8} Meta_e {18 9} Meta_E {18 10} Meta_e {18 11} Meta_E {18 12} Meta_Control_e {18 13} Meta_Control_e {18 14} Meta_Control_e {18 15} Meta_Control_e {18 16} e {18 17} E {18 18} e {18 19} E {18 20} Control_e {18 21} Control_e {18 22} Control_e {18 23} Control_e {18 24} Meta_e {18 25} Meta_E {18 26} Meta_e {18 27} Meta_E {18 28} Meta_Control_e {18 29} Meta_Control_e {18 30} Meta_Control_e {18 31} Meta_Control_e {18 32} e {18 33} E {18 34} e {18 35} E {18 36} Control_e {18 37} Control_e {18 38} Control_e {18 39} Control_e {18 40} Meta_e {18 41} Meta_E {18 42} Meta_e {18 43} Meta_E {18 44} Meta_Control_e {18 45} Meta_Control_e {18 46} Meta_Control_e {18 47} Meta_Control_e {18 48} e {18 49} E {18 50} e {18 51} E {18 52} Control_e {18 53} Control_e {18 54} Control_e {18 55} Control_e {18 56} Meta_e {18 57} Meta_E {18 58} Meta_e {18 59} Meta_E {18 60} Meta_Control_e {18 61} Meta_Control_e {18 62} Meta_Control_e {18 63} Meta_Control_e {18 64} E {18 65} e {18 66} E {18 67} e {18 68} Control_e {18 69} Control_e {18 70} Control_e {18 71} Control_e {18 72} Meta_e {18 73} Meta_E {18 74} Meta_e {18 75} Meta_E {18 76} Meta_Control_e {18 77} Meta_Control_e {18 78} Meta_Control_e {18 79} Meta_Control_e {18 80} E {18 81} e {18 82} E {18 83} e {18 84} Control_e {18 85} Control_e {18 86} Control_e {18 87} Control_e {18 88} Meta_e {18 89} Meta_E {18 90} Meta_e {18 91} Meta_E {18 92} Meta_Control_e {18 93} Meta_Control_e {18 94} Meta_Control_e {18 95} Meta_Control_e {18 96} E {18 97} e {18 98} E {18 99} e {18 100} Control_e {18 101} Control_e {18 102} Control_e {18 103} Control_e {18 104} Meta_e {18 105} Meta_E {18 106} Meta_e {18 107} Meta_E {18 108} Meta_Control_e {18 109} Meta_Control_e {18 110} Meta_Control_e {18 111} Meta_Control_e {18 112} E {18 113} e {18 114} E {18 115} e {18 116} Control_e {18 117} Control_e {18 118} Control_e {18 119} Control_e {18 120} Meta_e {18 121} Meta_E {18 122} Meta_e {18 123} Meta_E {18 124} Meta_Control_e {18 125} Meta_Control_e {18 126} Meta_Control_e {18 127} Meta_Control_e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} Control_r {19 5} Control_r {19 6} Control_r {19 7} Control_r {19 8} Meta_r {19 9} Meta_R {19 10} Meta_r {19 11} Meta_R {19 12} Meta_Control_r {19 13} Meta_Control_r {19 14} Meta_Control_r {19 15} Meta_Control_r {19 16} r {19 17} R {19 18} r {19 19} R {19 20} Control_r {19 21} Control_r {19 22} Control_r {19 23} Control_r {19 24} Meta_r {19 25} Meta_R {19 26} Meta_r {19 27} Meta_R {19 28} Meta_Control_r {19 29} Meta_Control_r {19 30} Meta_Control_r {19 31} Meta_Control_r {19 32} r {19 33} R {19 34} r {19 35} R {19 36} Control_r {19 37} Control_r {19 38} Control_r {19 39} Control_r {19 40} Meta_r {19 41} Meta_R {19 42} Meta_r {19 43} Meta_R {19 44} Meta_Control_r {19 45} Meta_Control_r {19 46} Meta_Control_r {19 47} Meta_Control_r {19 48} r {19 49} R {19 50} r {19 51} R {19 52} Control_r {19 53} Control_r {19 54} Control_r {19 55} Control_r {19 56} Meta_r {19 57} Meta_R {19 58} Meta_r {19 59} Meta_R {19 60} Meta_Control_r {19 61} Meta_Control_r {19 62} Meta_Control_r {19 63} Meta_Control_r {19 64} R {19 65} r {19 66} R {19 67} r {19 68} Control_r {19 69} Control_r {19 70} Control_r {19 71} Control_r {19 72} Meta_r {19 73} Meta_R {19 74} Meta_r {19 75} Meta_R {19 76} Meta_Control_r {19 77} Meta_Control_r {19 78} Meta_Control_r {19 79} Meta_Control_r {19 80} R {19 81} r {19 82} R {19 83} r {19 84} Control_r {19 85} Control_r {19 86} Control_r {19 87} Control_r {19 88} Meta_r {19 89} Meta_R {19 90} Meta_r {19 91} Meta_R {19 92} Meta_Control_r {19 93} Meta_Control_r {19 94} Meta_Control_r {19 95} Meta_Control_r {19 96} R {19 97} r {19 98} R {19 99} r {19 100} Control_r {19 101} Control_r {19 102} Control_r {19 103} Control_r {19 104} Meta_r {19 105} Meta_R {19 106} Meta_r {19 107} Meta_R {19 108} Meta_Control_r {19 109} Meta_Control_r {19 110} Meta_Control_r {19 111} Meta_Control_r {19 112} R {19 113} r {19 114} R {19 115} r {19 116} Control_r {19 117} Control_r {19 118} Control_r {19 119} Control_r {19 120} Meta_r {19 121} Meta_R {19 122} Meta_r {19 123} Meta_R {19 124} Meta_Control_r {19 125} Meta_Control_r {19 126} Meta_Control_r {19 127} Meta_Control_r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} Control_t {20 5} Control_t {20 6} Control_t {20 7} Control_t {20 8} Meta_t {20 9} Meta_T {20 10} Meta_t {20 11} Meta_T {20 12} Meta_Control_t {20 13} Meta_Control_t {20 14} Meta_Control_t {20 15} Meta_Control_t {20 16} t {20 17} T {20 18} t {20 19} T {20 20} Control_t {20 21} Control_t {20 22} Control_t {20 23} Control_t {20 24} Meta_t {20 25} Meta_T {20 26} Meta_t {20 27} Meta_T {20 28} Meta_Control_t {20 29} Meta_Control_t {20 30} Meta_Control_t {20 31} Meta_Control_t {20 32} t {20 33} T {20 34} t {20 35} T {20 36} Control_t {20 37} Control_t {20 38} Control_t {20 39} Control_t {20 40} Meta_t {20 41} Meta_T {20 42} Meta_t {20 43} Meta_T {20 44} Meta_Control_t {20 45} Meta_Control_t {20 46} Meta_Control_t {20 47} Meta_Control_t {20 48} t {20 49} T {20 50} t {20 51} T {20 52} Control_t {20 53} Control_t {20 54} Control_t {20 55} Control_t {20 56} Meta_t {20 57} Meta_T {20 58} Meta_t {20 59} Meta_T {20 60} Meta_Control_t {20 61} Meta_Control_t {20 62} Meta_Control_t {20 63} Meta_Control_t {20 64} T {20 65} t {20 66} T {20 67} t {20 68} Control_t {20 69} Control_t {20 70} Control_t {20 71} Control_t {20 72} Meta_t {20 73} Meta_T {20 74} Meta_t {20 75} Meta_T {20 76} Meta_Control_t {20 77} Meta_Control_t {20 78} Meta_Control_t {20 79} Meta_Control_t {20 80} T {20 81} t {20 82} T {20 83} t {20 84} Control_t {20 85} Control_t {20 86} Control_t {20 87} Control_t {20 88} Meta_t {20 89} Meta_T {20 90} Meta_t {20 91} Meta_T {20 92} Meta_Control_t {20 93} Meta_Control_t {20 94} Meta_Control_t {20 95} Meta_Control_t {20 96} T {20 97} t {20 98} T {20 99} t {20 100} Control_t {20 101} Control_t {20 102} Control_t {20 103} Control_t {20 104} Meta_t {20 105} Meta_T {20 106} Meta_t {20 107} Meta_T {20 108} Meta_Control_t {20 109} Meta_Control_t {20 110} Meta_Control_t {20 111} Meta_Control_t {20 112} T {20 113} t {20 114} T {20 115} t {20 116} Control_t {20 117} Control_t {20 118} Control_t {20 119} Control_t {20 120} Meta_t {20 121} Meta_T {20 122} Meta_t {20 123} Meta_T {20 124} Meta_Control_t {20 125} Meta_Control_t {20 126} Meta_Control_t {20 127} Meta_Control_t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} Control_y {21 5} Control_y {21 6} Control_y {21 7} Control_y {21 8} Meta_y {21 9} Meta_Y {21 10} Meta_y {21 11} Meta_Y {21 12} Meta_Control_y {21 13} Meta_Control_y {21 14} Meta_Control_y {21 15} Meta_Control_y {21 16} y {21 17} Y {21 18} y {21 19} Y {21 20} Control_y {21 21} Control_y {21 22} Control_y {21 23} Control_y {21 24} Meta_y {21 25} Meta_Y {21 26} Meta_y {21 27} Meta_Y {21 28} Meta_Control_y {21 29} Meta_Control_y {21 30} Meta_Control_y {21 31} Meta_Control_y {21 32} y {21 33} Y {21 34} y {21 35} Y {21 36} Control_y {21 37} Control_y {21 38} Control_y {21 39} Control_y {21 40} Meta_y {21 41} Meta_Y {21 42} Meta_y {21 43} Meta_Y {21 44} Meta_Control_y {21 45} Meta_Control_y {21 46} Meta_Control_y {21 47} Meta_Control_y {21 48} y {21 49} Y {21 50} y {21 51} Y {21 52} Control_y {21 53} Control_y {21 54} Control_y {21 55} Control_y {21 56} Meta_y {21 57} Meta_Y {21 58} Meta_y {21 59} Meta_Y {21 60} Meta_Control_y {21 61} Meta_Control_y {21 62} Meta_Control_y {21 63} Meta_Control_y {21 64} Y {21 65} y {21 66} Y {21 67} y {21 68} Control_y {21 69} Control_y {21 70} Control_y {21 71} Control_y {21 72} Meta_y {21 73} Meta_Y {21 74} Meta_y {21 75} Meta_Y {21 76} Meta_Control_y {21 77} Meta_Control_y {21 78} Meta_Control_y {21 79} Meta_Control_y {21 80} Y {21 81} y {21 82} Y {21 83} y {21 84} Control_y {21 85} Control_y {21 86} Control_y {21 87} Control_y {21 88} Meta_y {21 89} Meta_Y {21 90} Meta_y {21 91} Meta_Y {21 92} Meta_Control_y {21 93} Meta_Control_y {21 94} Meta_Control_y {21 95} Meta_Control_y {21 96} Y {21 97} y {21 98} Y {21 99} y {21 100} Control_y {21 101} Control_y {21 102} Control_y {21 103} Control_y {21 104} Meta_y {21 105} Meta_Y {21 106} Meta_y {21 107} Meta_Y {21 108} Meta_Control_y {21 109} Meta_Control_y {21 110} Meta_Control_y {21 111} Meta_Control_y {21 112} Y {21 113} y {21 114} Y {21 115} y {21 116} Control_y {21 117} Control_y {21 118} Control_y {21 119} Control_y {21 120} Meta_y {21 121} Meta_Y {21 122} Meta_y {21 123} Meta_Y {21 124} Meta_Control_y {21 125} Meta_Control_y {21 126} Meta_Control_y {21 127} Meta_Control_y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} Control_u {22 5} Control_u {22 6} Control_u {22 7} Control_u {22 8} Meta_u {22 9} Meta_U {22 10} Meta_u {22 11} Meta_U {22 12} Meta_Control_u {22 13} Meta_Control_u {22 14} Meta_Control_u {22 15} Meta_Control_u {22 16} u {22 17} U {22 18} u {22 19} U {22 20} Control_u {22 21} Control_u {22 22} Control_u {22 23} Control_u {22 24} Meta_u {22 25} Meta_U {22 26} Meta_u {22 27} Meta_U {22 28} Meta_Control_u {22 29} Meta_Control_u {22 30} Meta_Control_u {22 31} Meta_Control_u {22 32} u {22 33} U {22 34} u {22 35} U {22 36} Control_u {22 37} Control_u {22 38} Control_u {22 39} Control_u {22 40} Meta_u {22 41} Meta_U {22 42} Meta_u {22 43} Meta_U {22 44} Meta_Control_u {22 45} Meta_Control_u {22 46} Meta_Control_u {22 47} Meta_Control_u {22 48} u {22 49} U {22 50} u {22 51} U {22 52} Control_u {22 53} Control_u {22 54} Control_u {22 55} Control_u {22 56} Meta_u {22 57} Meta_U {22 58} Meta_u {22 59} Meta_U {22 60} Meta_Control_u {22 61} Meta_Control_u {22 62} Meta_Control_u {22 63} Meta_Control_u {22 64} U {22 65} u {22 66} U {22 67} u {22 68} Control_u {22 69} Control_u {22 70} Control_u {22 71} Control_u {22 72} Meta_u {22 73} Meta_U {22 74} Meta_u {22 75} Meta_U {22 76} Meta_Control_u {22 77} Meta_Control_u {22 78} Meta_Control_u {22 79} Meta_Control_u {22 80} U {22 81} u {22 82} U {22 83} u {22 84} Control_u {22 85} Control_u {22 86} Control_u {22 87} Control_u {22 88} Meta_u {22 89} Meta_U {22 90} Meta_u {22 91} Meta_U {22 92} Meta_Control_u {22 93} Meta_Control_u {22 94} Meta_Control_u {22 95} Meta_Control_u {22 96} U {22 97} u {22 98} U {22 99} u {22 100} Control_u {22 101} Control_u {22 102} Control_u {22 103} Control_u {22 104} Meta_u {22 105} Meta_U {22 106} Meta_u {22 107} Meta_U {22 108} Meta_Control_u {22 109} Meta_Control_u {22 110} Meta_Control_u {22 111} Meta_Control_u {22 112} U {22 113} u {22 114} U {22 115} u {22 116} Control_u {22 117} Control_u {22 118} Control_u {22 119} Control_u {22 120} Meta_u {22 121} Meta_U {22 122} Meta_u {22 123} Meta_U {22 124} Meta_Control_u {22 125} Meta_Control_u {22 126} Meta_Control_u {22 127} Meta_Control_u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} Tab {23 5} Tab {23 6} Tab {23 7} Tab {23 8} Meta_i {23 9} Meta_I {23 10} Meta_i {23 11} Meta_I {23 12} Meta_Tab {23 13} Meta_Tab {23 14} Meta_Tab {23 15} Meta_Tab {23 16} i {23 17} I {23 18} i {23 19} I {23 20} Tab {23 21} Tab {23 22} Tab {23 23} Tab {23 24} Meta_i {23 25} Meta_I {23 26} Meta_i {23 27} Meta_I {23 28} Meta_Tab {23 29} Meta_Tab {23 30} Meta_Tab {23 31} Meta_Tab {23 32} i {23 33} I {23 34} i {23 35} I {23 36} Tab {23 37} Tab {23 38} Tab {23 39} Tab {23 40} Meta_i {23 41} Meta_I {23 42} Meta_i {23 43} Meta_I {23 44} Meta_Tab {23 45} Meta_Tab {23 46} Meta_Tab {23 47} Meta_Tab {23 48} i {23 49} I {23 50} i {23 51} I {23 52} Tab {23 53} Tab {23 54} Tab {23 55} Tab {23 56} Meta_i {23 57} Meta_I {23 58} Meta_i {23 59} Meta_I {23 60} Meta_Tab {23 61} Meta_Tab {23 62} Meta_Tab {23 63} Meta_Tab {23 64} I {23 65} i {23 66} I {23 67} i {23 68} Tab {23 69} Tab {23 70} Tab {23 71} Tab {23 72} Meta_i {23 73} Meta_I {23 74} Meta_i {23 75} Meta_I {23 76} Meta_Tab {23 77} Meta_Tab {23 78} Meta_Tab {23 79} Meta_Tab {23 80} I {23 81} i {23 82} I {23 83} i {23 84} Tab {23 85} Tab {23 86} Tab {23 87} Tab {23 88} Meta_i {23 89} Meta_I {23 90} Meta_i {23 91} Meta_I {23 92} Meta_Tab {23 93} Meta_Tab {23 94} Meta_Tab {23 95} Meta_Tab {23 96} I {23 97} i {23 98} I {23 99} i {23 100} Tab {23 101} Tab {23 102} Tab {23 103} Tab {23 104} Meta_i {23 105} Meta_I {23 106} Meta_i {23 107} Meta_I {23 108} Meta_Tab {23 109} Meta_Tab {23 110} Meta_Tab {23 111} Meta_Tab {23 112} I {23 113} i {23 114} I {23 115} i {23 116} Tab {23 117} Tab {23 118} Tab {23 119} Tab {23 120} Meta_i {23 121} Meta_I {23 122} Meta_i {23 123} Meta_I {23 124} Meta_Tab {23 125} Meta_Tab {23 126} Meta_Tab {23 127} Meta_Tab {24 0} o {24 1} O {24 2} o {24 3} O {24 4} Control_o {24 5} Control_o {24 6} Control_o {24 7} Control_o {24 8} Meta_o {24 9} Meta_O {24 10} Meta_o {24 11} Meta_O {24 12} Meta_Control_o {24 13} Meta_Control_o {24 14} Meta_Control_o {24 15} Meta_Control_o {24 16} o {24 17} O {24 18} o {24 19} O {24 20} Control_o {24 21} Control_o {24 22} Control_o {24 23} Control_o {24 24} Meta_o {24 25} Meta_O {24 26} Meta_o {24 27} Meta_O {24 28} Meta_Control_o {24 29} Meta_Control_o {24 30} Meta_Control_o {24 31} Meta_Control_o {24 32} o {24 33} O {24 34} o {24 35} O {24 36} Control_o {24 37} Control_o {24 38} Control_o {24 39} Control_o {24 40} Meta_o {24 41} Meta_O {24 42} Meta_o {24 43} Meta_O {24 44} Meta_Control_o {24 45} Meta_Control_o {24 46} Meta_Control_o {24 47} Meta_Control_o {24 48} o {24 49} O {24 50} o {24 51} O {24 52} Control_o {24 53} Control_o {24 54} Control_o {24 55} Control_o {24 56} Meta_o {24 57} Meta_O {24 58} Meta_o {24 59} Meta_O {24 60} Meta_Control_o {24 61} Meta_Control_o {24 62} Meta_Control_o {24 63} Meta_Control_o {24 64} O {24 65} o {24 66} O {24 67} o {24 68} Control_o {24 69} Control_o {24 70} Control_o {24 71} Control_o {24 72} Meta_o {24 73} Meta_O {24 74} Meta_o {24 75} Meta_O {24 76} Meta_Control_o {24 77} Meta_Control_o {24 78} Meta_Control_o {24 79} Meta_Control_o {24 80} O {24 81} o {24 82} O {24 83} o {24 84} Control_o {24 85} Control_o {24 86} Control_o {24 87} Control_o {24 88} Meta_o {24 89} Meta_O {24 90} Meta_o {24 91} Meta_O {24 92} Meta_Control_o {24 93} Meta_Control_o {24 94} Meta_Control_o {24 95} Meta_Control_o {24 96} O {24 97} o {24 98} O {24 99} o {24 100} Control_o {24 101} Control_o {24 102} Control_o {24 103} Control_o {24 104} Meta_o {24 105} Meta_O {24 106} Meta_o {24 107} Meta_O {24 108} Meta_Control_o {24 109} Meta_Control_o {24 110} Meta_Control_o {24 111} Meta_Control_o {24 112} O {24 113} o {24 114} O {24 115} o {24 116} Control_o {24 117} Control_o {24 118} Control_o {24 119} Control_o {24 120} Meta_o {24 121} Meta_O {24 122} Meta_o {24 123} Meta_O {24 124} Meta_Control_o {24 125} Meta_Control_o {24 126} Meta_Control_o {24 127} Meta_Control_o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} Control_p {25 5} Control_p {25 6} Control_p {25 7} Control_p {25 8} Meta_p {25 9} Meta_P {25 10} Meta_p {25 11} Meta_P {25 12} Meta_Control_p {25 13} Meta_Control_p {25 14} Meta_Control_p {25 15} Meta_Control_p {25 16} p {25 17} P {25 18} p {25 19} P {25 20} Control_p {25 21} Control_p {25 22} Control_p {25 23} Control_p {25 24} Meta_p {25 25} Meta_P {25 26} Meta_p {25 27} Meta_P {25 28} Meta_Control_p {25 29} Meta_Control_p {25 30} Meta_Control_p {25 31} Meta_Control_p {25 32} p {25 33} P {25 34} p {25 35} P {25 36} Control_p {25 37} Control_p {25 38} Control_p {25 39} Control_p {25 40} Meta_p {25 41} Meta_P {25 42} Meta_p {25 43} Meta_P {25 44} Meta_Control_p {25 45} Meta_Control_p {25 46} Meta_Control_p {25 47} Meta_Control_p {25 48} p {25 49} P {25 50} p {25 51} P {25 52} Control_p {25 53} Control_p {25 54} Control_p {25 55} Control_p {25 56} Meta_p {25 57} Meta_P {25 58} Meta_p {25 59} Meta_P {25 60} Meta_Control_p {25 61} Meta_Control_p {25 62} Meta_Control_p {25 63} Meta_Control_p {25 64} P {25 65} p {25 66} P {25 67} p {25 68} Control_p {25 69} Control_p {25 70} Control_p {25 71} Control_p {25 72} Meta_p {25 73} Meta_P {25 74} Meta_p {25 75} Meta_P {25 76} Meta_Control_p {25 77} Meta_Control_p {25 78} Meta_Control_p {25 79} Meta_Control_p {25 80} P {25 81} p {25 82} P {25 83} p {25 84} Control_p {25 85} Control_p {25 86} Control_p {25 87} Control_p {25 88} Meta_p {25 89} Meta_P {25 90} Meta_p {25 91} Meta_P {25 92} Meta_Control_p {25 93} Meta_Control_p {25 94} Meta_Control_p {25 95} Meta_Control_p {25 96} P {25 97} p {25 98} P {25 99} p {25 100} Control_p {25 101} Control_p {25 102} Control_p {25 103} Control_p {25 104} Meta_p {25 105} Meta_P {25 106} Meta_p {25 107} Meta_P {25 108} Meta_Control_p {25 109} Meta_Control_p {25 110} Meta_Control_p {25 111} Meta_Control_p {25 112} P {25 113} p {25 114} P {25 115} p {25 116} Control_p {25 117} Control_p {25 118} Control_p {25 119} Control_p {25 120} Meta_p {25 121} Meta_P {25 122} Meta_p {25 123} Meta_P {25 124} Meta_Control_p {25 125} Meta_Control_p {25 126} Meta_Control_p {25 127} Meta_Control_p {26 0} bracketleft {26 1} braceleft {26 2} bracketleft {26 3} braceleft {26 4} Escape {26 5} Escape {26 6} Escape {26 7} Escape {26 8} Meta_bracketleft {26 9} Meta_braceleft {26 10} Meta_bracketleft {26 11} Meta_braceleft {26 12} Meta_Escape {26 13} Meta_Escape {26 14} Meta_Escape {26 15} Meta_Escape {26 16} bracketleft {26 17} braceleft {26 18} bracketleft {26 19} braceleft {26 20} Escape {26 21} Escape {26 22} Escape {26 23} Escape {26 24} Meta_bracketleft {26 25} Meta_braceleft {26 26} Meta_bracketleft {26 27} Meta_braceleft {26 28} Meta_Escape {26 29} Meta_Escape {26 30} Meta_Escape {26 31} Meta_Escape {26 32} bracketleft {26 33} braceleft {26 34} bracketleft {26 35} braceleft {26 36} Escape {26 37} Escape {26 38} Escape {26 39} Escape {26 40} Meta_bracketleft {26 41} Meta_braceleft {26 42} Meta_bracketleft {26 43} Meta_braceleft {26 44} Meta_Escape {26 45} Meta_Escape {26 46} Meta_Escape {26 47} Meta_Escape {26 48} bracketleft {26 49} braceleft {26 50} bracketleft {26 51} braceleft {26 52} Escape {26 53} Escape {26 54} Escape {26 55} Escape {26 56} Meta_bracketleft {26 57} Meta_braceleft {26 58} Meta_bracketleft {26 59} Meta_braceleft {26 60} Meta_Escape {26 61} Meta_Escape {26 62} Meta_Escape {26 63} Meta_Escape {26 64} bracketleft {26 65} braceleft {26 66} bracketleft {26 67} braceleft {26 68} Escape {26 69} Escape {26 70} Escape {26 71} Escape {26 72} Meta_bracketleft {26 73} Meta_braceleft {26 74} Meta_bracketleft {26 75} Meta_braceleft {26 76} Meta_Escape {26 77} Meta_Escape {26 78} Meta_Escape {26 79} Meta_Escape {26 80} bracketleft {26 81} braceleft {26 82} bracketleft {26 83} braceleft {26 84} Escape {26 85} Escape {26 86} Escape {26 87} Escape {26 88} Meta_bracketleft {26 89} Meta_braceleft {26 90} Meta_bracketleft {26 91} Meta_braceleft {26 92} Meta_Escape {26 93} Meta_Escape {26 94} Meta_Escape {26 95} Meta_Escape {26 96} bracketleft {26 97} braceleft {26 98} bracketleft {26 99} braceleft {26 100} Escape {26 101} Escape {26 102} Escape {26 103} Escape {26 104} Meta_bracketleft {26 105} Meta_braceleft {26 106} Meta_bracketleft {26 107} Meta_braceleft {26 108} Meta_Escape {26 109} Meta_Escape {26 110} Meta_Escape {26 111} Meta_Escape {26 112} bracketleft {26 113} braceleft {26 114} bracketleft {26 115} braceleft {26 116} Escape {26 117} Escape {26 118} Escape {26 119} Escape {26 120} Meta_bracketleft {26 121} Meta_braceleft {26 122} Meta_bracketleft {26 123} Meta_braceleft {26 124} Meta_Escape {26 125} Meta_Escape {26 126} Meta_Escape {26 127} Meta_Escape {27 0} bracketright {27 1} braceright {27 2} bracketright {27 3} braceright {27 4} Control_bracketright {27 5} Control_bracketright {27 6} Control_bracketright {27 7} Control_bracketright {27 8} Meta_bracketright {27 9} Meta_braceright {27 10} Meta_bracketright {27 11} Meta_braceright {27 12} Meta_Control_bracketright {27 13} Meta_Control_bracketright {27 14} Meta_Control_bracketright {27 15} Meta_Control_bracketright {27 16} bracketright {27 17} braceright {27 18} bracketright {27 19} braceright {27 20} Control_bracketright {27 21} Control_bracketright {27 22} Control_bracketright {27 23} Control_bracketright {27 24} Meta_bracketright {27 25} Meta_braceright {27 26} Meta_bracketright {27 27} Meta_braceright {27 28} Meta_Control_bracketright {27 29} Meta_Control_bracketright {27 30} Meta_Control_bracketright {27 31} Meta_Control_bracketright {27 32} bracketright {27 33} braceright {27 34} bracketright {27 35} braceright {27 36} Control_bracketright {27 37} Control_bracketright {27 38} Control_bracketright {27 39} Control_bracketright {27 40} Meta_bracketright {27 41} Meta_braceright {27 42} Meta_bracketright {27 43} Meta_braceright {27 44} Meta_Control_bracketright {27 45} Meta_Control_bracketright {27 46} Meta_Control_bracketright {27 47} Meta_Control_bracketright {27 48} bracketright {27 49} braceright {27 50} bracketright {27 51} braceright {27 52} Control_bracketright {27 53} Control_bracketright {27 54} Control_bracketright {27 55} Control_bracketright {27 56} Meta_bracketright {27 57} Meta_braceright {27 58} Meta_bracketright {27 59} Meta_braceright {27 60} Meta_Control_bracketright {27 61} Meta_Control_bracketright {27 62} Meta_Control_bracketright {27 63} Meta_Control_bracketright {27 64} bracketright {27 65} braceright {27 66} bracketright {27 67} braceright {27 68} Control_bracketright {27 69} Control_bracketright {27 70} Control_bracketright {27 71} Control_bracketright {27 72} Meta_bracketright {27 73} Meta_braceright {27 74} Meta_bracketright {27 75} Meta_braceright {27 76} Meta_Control_bracketright {27 77} Meta_Control_bracketright {27 78} Meta_Control_bracketright {27 79} Meta_Control_bracketright {27 80} bracketright {27 81} braceright {27 82} bracketright {27 83} braceright {27 84} Control_bracketright {27 85} Control_bracketright {27 86} Control_bracketright {27 87} Control_bracketright {27 88} Meta_bracketright {27 89} Meta_braceright {27 90} Meta_bracketright {27 91} Meta_braceright {27 92} Meta_Control_bracketright {27 93} Meta_Control_bracketright {27 94} Meta_Control_bracketright {27 95} Meta_Control_bracketright {27 96} bracketright {27 97} braceright {27 98} bracketright {27 99} braceright {27 100} Control_bracketright {27 101} Control_bracketright {27 102} Control_bracketright {27 103} Control_bracketright {27 104} Meta_bracketright {27 105} Meta_braceright {27 106} Meta_bracketright {27 107} Meta_braceright {27 108} Meta_Control_bracketright {27 109} Meta_Control_bracketright {27 110} Meta_Control_bracketright {27 111} Meta_Control_bracketright {27 112} bracketright {27 113} braceright {27 114} bracketright {27 115} braceright {27 116} Control_bracketright {27 117} Control_bracketright {27 118} Control_bracketright {27 119} Control_bracketright {27 120} Meta_bracketright {27 121} Meta_braceright {27 122} Meta_bracketright {27 123} Meta_braceright {27 124} Meta_Control_bracketright {27 125} Meta_Control_bracketright {27 126} Meta_Control_bracketright {27 127} Meta_Control_bracketright {28 0} Return {28 1} Return {28 2} Return {28 3} Return {28 4} Control_m {28 5} Control_m {28 6} Control_m {28 7} Control_m {28 8} Meta_Control_m {28 9} Meta_Control_m {28 10} Meta_Control_m {28 11} Meta_Control_m {28 12} Meta_Control_m {28 13} Meta_Control_m {28 14} Meta_Control_m {28 15} Meta_Control_m {28 16} Return {28 17} Return {28 18} Return {28 19} Return {28 20} Control_m {28 21} Control_m {28 22} Control_m {28 23} Control_m {28 24} Meta_Control_m {28 25} Meta_Control_m {28 26} Meta_Control_m {28 27} Meta_Control_m {28 28} Meta_Control_m {28 29} Meta_Control_m {28 30} Meta_Control_m {28 31} Meta_Control_m {28 32} Return {28 33} Return {28 34} Return {28 35} Return {28 36} Control_m {28 37} Control_m {28 38} Control_m {28 39} Control_m {28 40} Meta_Control_m {28 41} Meta_Control_m {28 42} Meta_Control_m {28 43} Meta_Control_m {28 44} Meta_Control_m {28 45} Meta_Control_m {28 46} Meta_Control_m {28 47} Meta_Control_m {28 48} Return {28 49} Return {28 50} Return {28 51} Return {28 52} Control_m {28 53} Control_m {28 54} Control_m {28 55} Control_m {28 56} Meta_Control_m {28 57} Meta_Control_m {28 58} Meta_Control_m {28 59} Meta_Control_m {28 60} Meta_Control_m {28 61} Meta_Control_m {28 62} Meta_Control_m {28 63} Meta_Control_m {28 64} Return {28 65} Return {28 66} Return {28 67} Return {28 68} Control_m {28 69} Control_m {28 70} Control_m {28 71} Control_m {28 72} Meta_Control_m {28 73} Meta_Control_m {28 74} Meta_Control_m {28 75} Meta_Control_m {28 76} Meta_Control_m {28 77} Meta_Control_m {28 78} Meta_Control_m {28 79} Meta_Control_m {28 80} Return {28 81} Return {28 82} Return {28 83} Return {28 84} Control_m {28 85} Control_m {28 86} Control_m {28 87} Control_m {28 88} Meta_Control_m {28 89} Meta_Control_m {28 90} Meta_Control_m {28 91} Meta_Control_m {28 92} Meta_Control_m {28 93} Meta_Control_m {28 94} Meta_Control_m {28 95} Meta_Control_m {28 96} Return {28 97} Return {28 98} Return {28 99} Return {28 100} Control_m {28 101} Control_m {28 102} Control_m {28 103} Control_m {28 104} Meta_Control_m {28 105} Meta_Control_m {28 106} Meta_Control_m {28 107} Meta_Control_m {28 108} Meta_Control_m {28 109} Meta_Control_m {28 110} Meta_Control_m {28 111} Meta_Control_m {28 112} Return {28 113} Return {28 114} Return {28 115} Return {28 116} Control_m {28 117} Control_m {28 118} Control_m {28 119} Control_m {28 120} Meta_Control_m {28 121} Meta_Control_m {28 122} Meta_Control_m {28 123} Meta_Control_m {28 124} Meta_Control_m {28 125} Meta_Control_m {28 126} Meta_Control_m {28 127} Meta_Control_m {29 0} Control {29 1} Control {29 2} Control {29 3} Control {29 4} Control {29 5} Control {29 6} Control {29 7} Control {29 8} Control {29 9} Control {29 10} Control {29 11} Control {29 12} Control {29 13} Control {29 14} Control {29 15} Control {29 16} Control {29 17} Control {29 18} Control {29 19} Control {29 20} Control {29 21} Control {29 22} Control {29 23} Control {29 24} Control {29 25} Control {29 26} Control {29 27} Control {29 28} Control {29 29} Control {29 30} Control {29 31} Control {29 32} Control {29 33} Control {29 34} Control {29 35} Control {29 36} Control {29 37} Control {29 38} Control {29 39} Control {29 40} Control {29 41} Control {29 42} Control {29 43} Control {29 44} Control {29 45} Control {29 46} Control {29 47} Control {29 48} Control {29 49} Control {29 50} Control {29 51} Control {29 52} Control {29 53} Control {29 54} Control {29 55} Control {29 56} Control {29 57} Control {29 58} Control {29 59} Control {29 60} Control {29 61} Control {29 62} Control {29 63} Control {29 64} Control {29 65} Control {29 66} Control {29 67} Control {29 68} Control {29 69} Control {29 70} Control {29 71} Control {29 72} Control {29 73} Control {29 74} Control {29 75} Control {29 76} Control {29 77} Control {29 78} Control {29 79} Control {29 80} Control {29 81} Control {29 82} Control {29 83} Control {29 84} Control {29 85} Control {29 86} Control {29 87} Control {29 88} Control {29 89} Control {29 90} Control {29 91} Control {29 92} Control {29 93} Control {29 94} Control {29 95} Control {29 96} Control {29 97} Control {29 98} Control {29 99} Control {29 100} Control {29 101} Control {29 102} Control {29 103} Control {29 104} Control {29 105} Control {29 106} Control {29 107} Control {29 108} Control {29 109} Control {29 110} Control {29 111} Control {29 112} Control {29 113} Control {29 114} Control {29 115} Control {29 116} Control {29 117} Control {29 118} Control {29 119} Control {29 120} Control {29 121} Control {29 122} Control {29 123} Control {29 124} Control {29 125} Control {29 126} Control {29 127} Control {30 0} a {30 1} A {30 2} a {30 3} A {30 4} Control_a {30 5} Control_a {30 6} Control_a {30 7} Control_a {30 8} Meta_a {30 9} Meta_A {30 10} Meta_a {30 11} Meta_A {30 12} Meta_Control_a {30 13} Meta_Control_a {30 14} Meta_Control_a {30 15} Meta_Control_a {30 16} a {30 17} A {30 18} a {30 19} A {30 20} Control_a {30 21} Control_a {30 22} Control_a {30 23} Control_a {30 24} Meta_a {30 25} Meta_A {30 26} Meta_a {30 27} Meta_A {30 28} Meta_Control_a {30 29} Meta_Control_a {30 30} Meta_Control_a {30 31} Meta_Control_a {30 32} a {30 33} A {30 34} a {30 35} A {30 36} Control_a {30 37} Control_a {30 38} Control_a {30 39} Control_a {30 40} Meta_a {30 41} Meta_A {30 42} Meta_a {30 43} Meta_A {30 44} Meta_Control_a {30 45} Meta_Control_a {30 46} Meta_Control_a {30 47} Meta_Control_a {30 48} a {30 49} A {30 50} a {30 51} A {30 52} Control_a {30 53} Control_a {30 54} Control_a {30 55} Control_a {30 56} Meta_a {30 57} Meta_A {30 58} Meta_a {30 59} Meta_A {30 60} Meta_Control_a {30 61} Meta_Control_a {30 62} Meta_Control_a {30 63} Meta_Control_a {30 64} A {30 65} a {30 66} A {30 67} a {30 68} Control_a {30 69} Control_a {30 70} Control_a {30 71} Control_a {30 72} Meta_a {30 73} Meta_A {30 74} Meta_a {30 75} Meta_A {30 76} Meta_Control_a {30 77} Meta_Control_a {30 78} Meta_Control_a {30 79} Meta_Control_a {30 80} A {30 81} a {30 82} A {30 83} a {30 84} Control_a {30 85} Control_a {30 86} Control_a {30 87} Control_a {30 88} Meta_a {30 89} Meta_A {30 90} Meta_a {30 91} Meta_A {30 92} Meta_Control_a {30 93} Meta_Control_a {30 94} Meta_Control_a {30 95} Meta_Control_a {30 96} A {30 97} a {30 98} A {30 99} a {30 100} Control_a {30 101} Control_a {30 102} Control_a {30 103} Control_a {30 104} Meta_a {30 105} Meta_A {30 106} Meta_a {30 107} Meta_A {30 108} Meta_Control_a {30 109} Meta_Control_a {30 110} Meta_Control_a {30 111} Meta_Control_a {30 112} A {30 113} a {30 114} A {30 115} a {30 116} Control_a {30 117} Control_a {30 118} Control_a {30 119} Control_a {30 120} Meta_a {30 121} Meta_A {30 122} Meta_a {30 123} Meta_A {30 124} Meta_Control_a {30 125} Meta_Control_a {30 126} Meta_Control_a {30 127} Meta_Control_a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} Control_s {31 5} Control_s {31 6} Control_s {31 7} Control_s {31 8} Meta_s {31 9} Meta_S {31 10} Meta_s {31 11} Meta_S {31 12} Meta_Control_s {31 13} Meta_Control_s {31 14} Meta_Control_s {31 15} Meta_Control_s {31 16} s {31 17} S {31 18} s {31 19} S {31 20} Control_s {31 21} Control_s {31 22} Control_s {31 23} Control_s {31 24} Meta_s {31 25} Meta_S {31 26} Meta_s {31 27} Meta_S {31 28} Meta_Control_s {31 29} Meta_Control_s {31 30} Meta_Control_s {31 31} Meta_Control_s {31 32} s {31 33} S {31 34} s {31 35} S {31 36} Control_s {31 37} Control_s {31 38} Control_s {31 39} Control_s {31 40} Meta_s {31 41} Meta_S {31 42} Meta_s {31 43} Meta_S {31 44} Meta_Control_s {31 45} Meta_Control_s {31 46} Meta_Control_s {31 47} Meta_Control_s {31 48} s {31 49} S {31 50} s {31 51} S {31 52} Control_s {31 53} Control_s {31 54} Control_s {31 55} Control_s {31 56} Meta_s {31 57} Meta_S {31 58} Meta_s {31 59} Meta_S {31 60} Meta_Control_s {31 61} Meta_Control_s {31 62} Meta_Control_s {31 63} Meta_Control_s {31 64} S {31 65} s {31 66} S {31 67} s {31 68} Control_s {31 69} Control_s {31 70} Control_s {31 71} Control_s {31 72} Meta_s {31 73} Meta_S {31 74} Meta_s {31 75} Meta_S {31 76} Meta_Control_s {31 77} Meta_Control_s {31 78} Meta_Control_s {31 79} Meta_Control_s {31 80} S {31 81} s {31 82} S {31 83} s {31 84} Control_s {31 85} Control_s {31 86} Control_s {31 87} Control_s {31 88} Meta_s {31 89} Meta_S {31 90} Meta_s {31 91} Meta_S {31 92} Meta_Control_s {31 93} Meta_Control_s {31 94} Meta_Control_s {31 95} Meta_Control_s {31 96} S {31 97} s {31 98} S {31 99} s {31 100} Control_s {31 101} Control_s {31 102} Control_s {31 103} Control_s {31 104} Meta_s {31 105} Meta_S {31 106} Meta_s {31 107} Meta_S {31 108} Meta_Control_s {31 109} Meta_Control_s {31 110} Meta_Control_s {31 111} Meta_Control_s {31 112} S {31 113} s {31 114} S {31 115} s {31 116} Control_s {31 117} Control_s {31 118} Control_s {31 119} Control_s {31 120} Meta_s {31 121} Meta_S {31 122} Meta_s {31 123} Meta_S {31 124} Meta_Control_s {31 125} Meta_Control_s {31 126} Meta_Control_s {31 127} Meta_Control_s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} Control_d {32 5} Control_d {32 6} Control_d {32 7} Control_d {32 8} Meta_d {32 9} Meta_D {32 10} Meta_d {32 11} Meta_D {32 12} Meta_Control_d {32 13} Meta_Control_d {32 14} Meta_Control_d {32 15} Meta_Control_d {32 16} d {32 17} D {32 18} d {32 19} D {32 20} Control_d {32 21} Control_d {32 22} Control_d {32 23} Control_d {32 24} Meta_d {32 25} Meta_D {32 26} Meta_d {32 27} Meta_D {32 28} Meta_Control_d {32 29} Meta_Control_d {32 30} Meta_Control_d {32 31} Meta_Control_d {32 32} d {32 33} D {32 34} d {32 35} D {32 36} Control_d {32 37} Control_d {32 38} Control_d {32 39} Control_d {32 40} Meta_d {32 41} Meta_D {32 42} Meta_d {32 43} Meta_D {32 44} Meta_Control_d {32 45} Meta_Control_d {32 46} Meta_Control_d {32 47} Meta_Control_d {32 48} d {32 49} D {32 50} d {32 51} D {32 52} Control_d {32 53} Control_d {32 54} Control_d {32 55} Control_d {32 56} Meta_d {32 57} Meta_D {32 58} Meta_d {32 59} Meta_D {32 60} Meta_Control_d {32 61} Meta_Control_d {32 62} Meta_Control_d {32 63} Meta_Control_d {32 64} D {32 65} d {32 66} D {32 67} d {32 68} Control_d {32 69} Control_d {32 70} Control_d {32 71} Control_d {32 72} Meta_d {32 73} Meta_D {32 74} Meta_d {32 75} Meta_D {32 76} Meta_Control_d {32 77} Meta_Control_d {32 78} Meta_Control_d {32 79} Meta_Control_d {32 80} D {32 81} d {32 82} D {32 83} d {32 84} Control_d {32 85} Control_d {32 86} Control_d {32 87} Control_d {32 88} Meta_d {32 89} Meta_D {32 90} Meta_d {32 91} Meta_D {32 92} Meta_Control_d {32 93} Meta_Control_d {32 94} Meta_Control_d {32 95} Meta_Control_d {32 96} D {32 97} d {32 98} D {32 99} d {32 100} Control_d {32 101} Control_d {32 102} Control_d {32 103} Control_d {32 104} Meta_d {32 105} Meta_D {32 106} Meta_d {32 107} Meta_D {32 108} Meta_Control_d {32 109} Meta_Control_d {32 110} Meta_Control_d {32 111} Meta_Control_d {32 112} D {32 113} d {32 114} D {32 115} d {32 116} Control_d {32 117} Control_d {32 118} Control_d {32 119} Control_d {32 120} Meta_d {32 121} Meta_D {32 122} Meta_d {32 123} Meta_D {32 124} Meta_Control_d {32 125} Meta_Control_d {32 126} Meta_Control_d {32 127} Meta_Control_d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} Control_f {33 5} Control_f {33 6} Control_f {33 7} Control_f {33 8} Meta_f {33 9} Meta_F {33 10} Meta_f {33 11} Meta_F {33 12} Meta_Control_f {33 13} Meta_Control_f {33 14} Meta_Control_f {33 15} Meta_Control_f {33 16} f {33 17} F {33 18} f {33 19} F {33 20} Control_f {33 21} Control_f {33 22} Control_f {33 23} Control_f {33 24} Meta_f {33 25} Meta_F {33 26} Meta_f {33 27} Meta_F {33 28} Meta_Control_f {33 29} Meta_Control_f {33 30} Meta_Control_f {33 31} Meta_Control_f {33 32} f {33 33} F {33 34} f {33 35} F {33 36} Control_f {33 37} Control_f {33 38} Control_f {33 39} Control_f {33 40} Meta_f {33 41} Meta_F {33 42} Meta_f {33 43} Meta_F {33 44} Meta_Control_f {33 45} Meta_Control_f {33 46} Meta_Control_f {33 47} Meta_Control_f {33 48} f {33 49} F {33 50} f {33 51} F {33 52} Control_f {33 53} Control_f {33 54} Control_f {33 55} Control_f {33 56} Meta_f {33 57} Meta_F {33 58} Meta_f {33 59} Meta_F {33 60} Meta_Control_f {33 61} Meta_Control_f {33 62} Meta_Control_f {33 63} Meta_Control_f {33 64} F {33 65} f {33 66} F {33 67} f {33 68} Control_f {33 69} Control_f {33 70} Control_f {33 71} Control_f {33 72} Meta_f {33 73} Meta_F {33 74} Meta_f {33 75} Meta_F {33 76} Meta_Control_f {33 77} Meta_Control_f {33 78} Meta_Control_f {33 79} Meta_Control_f {33 80} F {33 81} f {33 82} F {33 83} f {33 84} Control_f {33 85} Control_f {33 86} Control_f {33 87} Control_f {33 88} Meta_f {33 89} Meta_F {33 90} Meta_f {33 91} Meta_F {33 92} Meta_Control_f {33 93} Meta_Control_f {33 94} Meta_Control_f {33 95} Meta_Control_f {33 96} F {33 97} f {33 98} F {33 99} f {33 100} Control_f {33 101} Control_f {33 102} Control_f {33 103} Control_f {33 104} Meta_f {33 105} Meta_F {33 106} Meta_f {33 107} Meta_F {33 108} Meta_Control_f {33 109} Meta_Control_f {33 110} Meta_Control_f {33 111} Meta_Control_f {33 112} F {33 113} f {33 114} F {33 115} f {33 116} Control_f {33 117} Control_f {33 118} Control_f {33 119} Control_f {33 120} Meta_f {33 121} Meta_F {33 122} Meta_f {33 123} Meta_F {33 124} Meta_Control_f {33 125} Meta_Control_f {33 126} Meta_Control_f {33 127} Meta_Control_f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} Control_g {34 5} Control_g {34 6} Control_g {34 7} Control_g {34 8} Meta_g {34 9} Meta_G {34 10} Meta_g {34 11} Meta_G {34 12} Meta_Control_g {34 13} Meta_Control_g {34 14} Meta_Control_g {34 15} Meta_Control_g {34 16} g {34 17} G {34 18} g {34 19} G {34 20} Control_g {34 21} Control_g {34 22} Control_g {34 23} Control_g {34 24} Meta_g {34 25} Meta_G {34 26} Meta_g {34 27} Meta_G {34 28} Meta_Control_g {34 29} Meta_Control_g {34 30} Meta_Control_g {34 31} Meta_Control_g {34 32} g {34 33} G {34 34} g {34 35} G {34 36} Control_g {34 37} Control_g {34 38} Control_g {34 39} Control_g {34 40} Meta_g {34 41} Meta_G {34 42} Meta_g {34 43} Meta_G {34 44} Meta_Control_g {34 45} Meta_Control_g {34 46} Meta_Control_g {34 47} Meta_Control_g {34 48} g {34 49} G {34 50} g {34 51} G {34 52} Control_g {34 53} Control_g {34 54} Control_g {34 55} Control_g {34 56} Meta_g {34 57} Meta_G {34 58} Meta_g {34 59} Meta_G {34 60} Meta_Control_g {34 61} Meta_Control_g {34 62} Meta_Control_g {34 63} Meta_Control_g {34 64} G {34 65} g {34 66} G {34 67} g {34 68} Control_g {34 69} Control_g {34 70} Control_g {34 71} Control_g {34 72} Meta_g {34 73} Meta_G {34 74} Meta_g {34 75} Meta_G {34 76} Meta_Control_g {34 77} Meta_Control_g {34 78} Meta_Control_g {34 79} Meta_Control_g {34 80} G {34 81} g {34 82} G {34 83} g {34 84} Control_g {34 85} Control_g {34 86} Control_g {34 87} Control_g {34 88} Meta_g {34 89} Meta_G {34 90} Meta_g {34 91} Meta_G {34 92} Meta_Control_g {34 93} Meta_Control_g {34 94} Meta_Control_g {34 95} Meta_Control_g {34 96} G {34 97} g {34 98} G {34 99} g {34 100} Control_g {34 101} Control_g {34 102} Control_g {34 103} Control_g {34 104} Meta_g {34 105} Meta_G {34 106} Meta_g {34 107} Meta_G {34 108} Meta_Control_g {34 109} Meta_Control_g {34 110} Meta_Control_g {34 111} Meta_Control_g {34 112} G {34 113} g {34 114} G {34 115} g {34 116} Control_g {34 117} Control_g {34 118} Control_g {34 119} Control_g {34 120} Meta_g {34 121} Meta_G {34 122} Meta_g {34 123} Meta_G {34 124} Meta_Control_g {34 125} Meta_Control_g {34 126} Meta_Control_g {34 127} Meta_Control_g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} BackSpace {35 5} BackSpace {35 6} BackSpace {35 7} BackSpace {35 8} Meta_h {35 9} Meta_H {35 10} Meta_h {35 11} Meta_H {35 12} Meta_BackSpace {35 13} Meta_BackSpace {35 14} Meta_BackSpace {35 15} Meta_BackSpace {35 16} h {35 17} H {35 18} h {35 19} H {35 20} BackSpace {35 21} BackSpace {35 22} BackSpace {35 23} BackSpace {35 24} Meta_h {35 25} Meta_H {35 26} Meta_h {35 27} Meta_H {35 28} Meta_BackSpace {35 29} Meta_BackSpace {35 30} Meta_BackSpace {35 31} Meta_BackSpace {35 32} h {35 33} H {35 34} h {35 35} H {35 36} BackSpace {35 37} BackSpace {35 38} BackSpace {35 39} BackSpace {35 40} Meta_h {35 41} Meta_H {35 42} Meta_h {35 43} Meta_H {35 44} Meta_BackSpace {35 45} Meta_BackSpace {35 46} Meta_BackSpace {35 47} Meta_BackSpace {35 48} h {35 49} H {35 50} h {35 51} H {35 52} BackSpace {35 53} BackSpace {35 54} BackSpace {35 55} BackSpace {35 56} Meta_h {35 57} Meta_H {35 58} Meta_h {35 59} Meta_H {35 60} Meta_BackSpace {35 61} Meta_BackSpace {35 62} Meta_BackSpace {35 63} Meta_BackSpace {35 64} H {35 65} h {35 66} H {35 67} h {35 68} BackSpace {35 69} BackSpace {35 70} BackSpace {35 71} BackSpace {35 72} Meta_h {35 73} Meta_H {35 74} Meta_h {35 75} Meta_H {35 76} Meta_BackSpace {35 77} Meta_BackSpace {35 78} Meta_BackSpace {35 79} Meta_BackSpace {35 80} H {35 81} h {35 82} H {35 83} h {35 84} BackSpace {35 85} BackSpace {35 86} BackSpace {35 87} BackSpace {35 88} Meta_h {35 89} Meta_H {35 90} Meta_h {35 91} Meta_H {35 92} Meta_BackSpace {35 93} Meta_BackSpace {35 94} Meta_BackSpace {35 95} Meta_BackSpace {35 96} H {35 97} h {35 98} H {35 99} h {35 100} BackSpace {35 101} BackSpace {35 102} BackSpace {35 103} BackSpace {35 104} Meta_h {35 105} Meta_H {35 106} Meta_h {35 107} Meta_H {35 108} Meta_BackSpace {35 109} Meta_BackSpace {35 110} Meta_BackSpace {35 111} Meta_BackSpace {35 112} H {35 113} h {35 114} H {35 115} h {35 116} BackSpace {35 117} BackSpace {35 118} BackSpace {35 119} BackSpace {35 120} Meta_h {35 121} Meta_H {35 122} Meta_h {35 123} Meta_H {35 124} Meta_BackSpace {35 125} Meta_BackSpace {35 126} Meta_BackSpace {35 127} Meta_BackSpace {36 0} j {36 1} J {36 2} j {36 3} J {36 4} Linefeed {36 5} Linefeed {36 6} Linefeed {36 7} Linefeed {36 8} Meta_j {36 9} Meta_J {36 10} Meta_j {36 11} Meta_J {36 12} Meta_Linefeed {36 13} Meta_Linefeed {36 14} Meta_Linefeed {36 15} Meta_Linefeed {36 16} j {36 17} J {36 18} j {36 19} J {36 20} Linefeed {36 21} Linefeed {36 22} Linefeed {36 23} Linefeed {36 24} Meta_j {36 25} Meta_J {36 26} Meta_j {36 27} Meta_J {36 28} Meta_Linefeed {36 29} Meta_Linefeed {36 30} Meta_Linefeed {36 31} Meta_Linefeed {36 32} j {36 33} J {36 34} j {36 35} J {36 36} Linefeed {36 37} Linefeed {36 38} Linefeed {36 39} Linefeed {36 40} Meta_j {36 41} Meta_J {36 42} Meta_j {36 43} Meta_J {36 44} Meta_Linefeed {36 45} Meta_Linefeed {36 46} Meta_Linefeed {36 47} Meta_Linefeed {36 48} j {36 49} J {36 50} j {36 51} J {36 52} Linefeed {36 53} Linefeed {36 54} Linefeed {36 55} Linefeed {36 56} Meta_j {36 57} Meta_J {36 58} Meta_j {36 59} Meta_J {36 60} Meta_Linefeed {36 61} Meta_Linefeed {36 62} Meta_Linefeed {36 63} Meta_Linefeed {36 64} J {36 65} j {36 66} J {36 67} j {36 68} Linefeed {36 69} Linefeed {36 70} Linefeed {36 71} Linefeed {36 72} Meta_j {36 73} Meta_J {36 74} Meta_j {36 75} Meta_J {36 76} Meta_Linefeed {36 77} Meta_Linefeed {36 78} Meta_Linefeed {36 79} Meta_Linefeed {36 80} J {36 81} j {36 82} J {36 83} j {36 84} Linefeed {36 85} Linefeed {36 86} Linefeed {36 87} Linefeed {36 88} Meta_j {36 89} Meta_J {36 90} Meta_j {36 91} Meta_J {36 92} Meta_Linefeed {36 93} Meta_Linefeed {36 94} Meta_Linefeed {36 95} Meta_Linefeed {36 96} J {36 97} j {36 98} J {36 99} j {36 100} Linefeed {36 101} Linefeed {36 102} Linefeed {36 103} Linefeed {36 104} Meta_j {36 105} Meta_J {36 106} Meta_j {36 107} Meta_J {36 108} Meta_Linefeed {36 109} Meta_Linefeed {36 110} Meta_Linefeed {36 111} Meta_Linefeed {36 112} J {36 113} j {36 114} J {36 115} j {36 116} Linefeed {36 117} Linefeed {36 118} Linefeed {36 119} Linefeed {36 120} Meta_j {36 121} Meta_J {36 122} Meta_j {36 123} Meta_J {36 124} Meta_Linefeed {36 125} Meta_Linefeed {36 126} Meta_Linefeed {36 127} Meta_Linefeed {37 0} k {37 1} K {37 2} k {37 3} K {37 4} Control_k {37 5} Control_k {37 6} Control_k {37 7} Control_k {37 8} Meta_k {37 9} Meta_K {37 10} Meta_k {37 11} Meta_K {37 12} Meta_Control_k {37 13} Meta_Control_k {37 14} Meta_Control_k {37 15} Meta_Control_k {37 16} k {37 17} K {37 18} k {37 19} K {37 20} Control_k {37 21} Control_k {37 22} Control_k {37 23} Control_k {37 24} Meta_k {37 25} Meta_K {37 26} Meta_k {37 27} Meta_K {37 28} Meta_Control_k {37 29} Meta_Control_k {37 30} Meta_Control_k {37 31} Meta_Control_k {37 32} k {37 33} K {37 34} k {37 35} K {37 36} Control_k {37 37} Control_k {37 38} Control_k {37 39} Control_k {37 40} Meta_k {37 41} Meta_K {37 42} Meta_k {37 43} Meta_K {37 44} Meta_Control_k {37 45} Meta_Control_k {37 46} Meta_Control_k {37 47} Meta_Control_k {37 48} k {37 49} K {37 50} k {37 51} K {37 52} Control_k {37 53} Control_k {37 54} Control_k {37 55} Control_k {37 56} Meta_k {37 57} Meta_K {37 58} Meta_k {37 59} Meta_K {37 60} Meta_Control_k {37 61} Meta_Control_k {37 62} Meta_Control_k {37 63} Meta_Control_k {37 64} K {37 65} k {37 66} K {37 67} k {37 68} Control_k {37 69} Control_k {37 70} Control_k {37 71} Control_k {37 72} Meta_k {37 73} Meta_K {37 74} Meta_k {37 75} Meta_K {37 76} Meta_Control_k {37 77} Meta_Control_k {37 78} Meta_Control_k {37 79} Meta_Control_k {37 80} K {37 81} k {37 82} K {37 83} k {37 84} Control_k {37 85} Control_k {37 86} Control_k {37 87} Control_k {37 88} Meta_k {37 89} Meta_K {37 90} Meta_k {37 91} Meta_K {37 92} Meta_Control_k {37 93} Meta_Control_k {37 94} Meta_Control_k {37 95} Meta_Control_k {37 96} K {37 97} k {37 98} K {37 99} k {37 100} Control_k {37 101} Control_k {37 102} Control_k {37 103} Control_k {37 104} Meta_k {37 105} Meta_K {37 106} Meta_k {37 107} Meta_K {37 108} Meta_Control_k {37 109} Meta_Control_k {37 110} Meta_Control_k {37 111} Meta_Control_k {37 112} K {37 113} k {37 114} K {37 115} k {37 116} Control_k {37 117} Control_k {37 118} Control_k {37 119} Control_k {37 120} Meta_k {37 121} Meta_K {37 122} Meta_k {37 123} Meta_K {37 124} Meta_Control_k {37 125} Meta_Control_k {37 126} Meta_Control_k {37 127} Meta_Control_k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} Control_l {38 5} Control_l {38 6} Control_l {38 7} Control_l {38 8} Meta_l {38 9} Meta_L {38 10} Meta_l {38 11} Meta_L {38 12} Meta_Control_l {38 13} Meta_Control_l {38 14} Meta_Control_l {38 15} Meta_Control_l {38 16} l {38 17} L {38 18} l {38 19} L {38 20} Control_l {38 21} Control_l {38 22} Control_l {38 23} Control_l {38 24} Meta_l {38 25} Meta_L {38 26} Meta_l {38 27} Meta_L {38 28} Meta_Control_l {38 29} Meta_Control_l {38 30} Meta_Control_l {38 31} Meta_Control_l {38 32} l {38 33} L {38 34} l {38 35} L {38 36} Control_l {38 37} Control_l {38 38} Control_l {38 39} Control_l {38 40} Meta_l {38 41} Meta_L {38 42} Meta_l {38 43} Meta_L {38 44} Meta_Control_l {38 45} Meta_Control_l {38 46} Meta_Control_l {38 47} Meta_Control_l {38 48} l {38 49} L {38 50} l {38 51} L {38 52} Control_l {38 53} Control_l {38 54} Control_l {38 55} Control_l {38 56} Meta_l {38 57} Meta_L {38 58} Meta_l {38 59} Meta_L {38 60} Meta_Control_l {38 61} Meta_Control_l {38 62} Meta_Control_l {38 63} Meta_Control_l {38 64} L {38 65} l {38 66} L {38 67} l {38 68} Control_l {38 69} Control_l {38 70} Control_l {38 71} Control_l {38 72} Meta_l {38 73} Meta_L {38 74} Meta_l {38 75} Meta_L {38 76} Meta_Control_l {38 77} Meta_Control_l {38 78} Meta_Control_l {38 79} Meta_Control_l {38 80} L {38 81} l {38 82} L {38 83} l {38 84} Control_l {38 85} Control_l {38 86} Control_l {38 87} Control_l {38 88} Meta_l {38 89} Meta_L {38 90} Meta_l {38 91} Meta_L {38 92} Meta_Control_l {38 93} Meta_Control_l {38 94} Meta_Control_l {38 95} Meta_Control_l {38 96} L {38 97} l {38 98} L {38 99} l {38 100} Control_l {38 101} Control_l {38 102} Control_l {38 103} Control_l {38 104} Meta_l {38 105} Meta_L {38 106} Meta_l {38 107} Meta_L {38 108} Meta_Control_l {38 109} Meta_Control_l {38 110} Meta_Control_l {38 111} Meta_Control_l {38 112} L {38 113} l {38 114} L {38 115} l {38 116} Control_l {38 117} Control_l {38 118} Control_l {38 119} Control_l {38 120} Meta_l {38 121} Meta_L {38 122} Meta_l {38 123} Meta_L {38 124} Meta_Control_l {38 125} Meta_Control_l {38 126} Meta_Control_l {38 127} Meta_Control_l {39 0} semicolon {39 1} colon {39 2} semicolon {39 3} colon {39 4} semicolon {39 5} colon {39 6} semicolon {39 7} colon {39 8} Meta_semicolon {39 9} Meta_colon {39 10} Meta_semicolon {39 11} Meta_colon {39 12} Meta_semicolon {39 13} Meta_colon {39 14} Meta_semicolon {39 15} Meta_colon {39 16} semicolon {39 17} colon {39 18} semicolon {39 19} colon {39 20} semicolon {39 21} colon {39 22} semicolon {39 23} colon {39 24} Meta_semicolon {39 25} Meta_colon {39 26} Meta_semicolon {39 27} Meta_colon {39 28} Meta_semicolon {39 29} Meta_colon {39 30} Meta_semicolon {39 31} Meta_colon {39 32} semicolon {39 33} colon {39 34} semicolon {39 35} colon {39 36} semicolon {39 37} colon {39 38} semicolon {39 39} colon {39 40} Meta_semicolon {39 41} Meta_colon {39 42} Meta_semicolon {39 43} Meta_colon {39 44} Meta_semicolon {39 45} Meta_colon {39 46} Meta_semicolon {39 47} Meta_colon {39 48} semicolon {39 49} colon {39 50} semicolon {39 51} colon {39 52} semicolon {39 53} colon {39 54} semicolon {39 55} colon {39 56} Meta_semicolon {39 57} Meta_colon {39 58} Meta_semicolon {39 59} Meta_colon {39 60} Meta_semicolon {39 61} Meta_colon {39 62} Meta_semicolon {39 63} Meta_colon {39 64} semicolon {39 65} colon {39 66} semicolon {39 67} colon {39 68} semicolon {39 69} colon {39 70} semicolon {39 71} colon {39 72} Meta_semicolon {39 73} Meta_colon {39 74} Meta_semicolon {39 75} Meta_colon {39 76} Meta_semicolon {39 77} Meta_colon {39 78} Meta_semicolon {39 79} Meta_colon {39 80} semicolon {39 81} colon {39 82} semicolon {39 83} colon {39 84} semicolon {39 85} colon {39 86} semicolon {39 87} colon {39 88} Meta_semicolon {39 89} Meta_colon {39 90} Meta_semicolon {39 91} Meta_colon {39 92} Meta_semicolon {39 93} Meta_colon {39 94} Meta_semicolon {39 95} Meta_colon {39 96} semicolon {39 97} colon {39 98} semicolon {39 99} colon {39 100} semicolon {39 101} colon {39 102} semicolon {39 103} colon {39 104} Meta_semicolon {39 105} Meta_colon {39 106} Meta_semicolon {39 107} Meta_colon {39 108} Meta_semicolon {39 109} Meta_colon {39 110} Meta_semicolon {39 111} Meta_colon {39 112} semicolon {39 113} colon {39 114} semicolon {39 115} colon {39 116} semicolon {39 117} colon {39 118} semicolon {39 119} colon {39 120} Meta_semicolon {39 121} Meta_colon {39 122} Meta_semicolon {39 123} Meta_colon {39 124} Meta_semicolon {39 125} Meta_colon {39 126} Meta_semicolon {39 127} Meta_colon {40 0} apostrophe {40 1} quotedbl {40 2} apostrophe {40 3} quotedbl {40 4} apostrophe {40 5} quotedbl {40 6} apostrophe {40 7} quotedbl {40 8} Meta_apostrophe {40 9} Meta_quotedbl {40 10} Meta_apostrophe {40 11} Meta_quotedbl {40 12} Meta_apostrophe {40 13} Meta_quotedbl {40 14} Meta_apostrophe {40 15} Meta_quotedbl {40 16} apostrophe {40 17} quotedbl {40 18} apostrophe {40 19} quotedbl {40 20} apostrophe {40 21} quotedbl {40 22} apostrophe {40 23} quotedbl {40 24} Meta_apostrophe {40 25} Meta_quotedbl {40 26} Meta_apostrophe {40 27} Meta_quotedbl {40 28} Meta_apostrophe {40 29} Meta_quotedbl {40 30} Meta_apostrophe {40 31} Meta_quotedbl {40 32} apostrophe {40 33} quotedbl {40 34} apostrophe {40 35} quotedbl {40 36} apostrophe {40 37} quotedbl {40 38} apostrophe {40 39} quotedbl {40 40} Meta_apostrophe {40 41} Meta_quotedbl {40 42} Meta_apostrophe {40 43} Meta_quotedbl {40 44} Meta_apostrophe {40 45} Meta_quotedbl {40 46} Meta_apostrophe {40 47} Meta_quotedbl {40 48} apostrophe {40 49} quotedbl {40 50} apostrophe {40 51} quotedbl {40 52} apostrophe {40 53} quotedbl {40 54} apostrophe {40 55} quotedbl {40 56} Meta_apostrophe {40 57} Meta_quotedbl {40 58} Meta_apostrophe {40 59} Meta_quotedbl {40 60} Meta_apostrophe {40 61} Meta_quotedbl {40 62} Meta_apostrophe {40 63} Meta_quotedbl {40 64} apostrophe {40 65} quotedbl {40 66} apostrophe {40 67} quotedbl {40 68} apostrophe {40 69} quotedbl {40 70} apostrophe {40 71} quotedbl {40 72} Meta_apostrophe {40 73} Meta_quotedbl {40 74} Meta_apostrophe {40 75} Meta_quotedbl {40 76} Meta_apostrophe {40 77} Meta_quotedbl {40 78} Meta_apostrophe {40 79} Meta_quotedbl {40 80} apostrophe {40 81} quotedbl {40 82} apostrophe {40 83} quotedbl {40 84} apostrophe {40 85} quotedbl {40 86} apostrophe {40 87} quotedbl {40 88} Meta_apostrophe {40 89} Meta_quotedbl {40 90} Meta_apostrophe {40 91} Meta_quotedbl {40 92} Meta_apostrophe {40 93} Meta_quotedbl {40 94} Meta_apostrophe {40 95} Meta_quotedbl {40 96} apostrophe {40 97} quotedbl {40 98} apostrophe {40 99} quotedbl {40 100} apostrophe {40 101} quotedbl {40 102} apostrophe {40 103} quotedbl {40 104} Meta_apostrophe {40 105} Meta_quotedbl {40 106} Meta_apostrophe {40 107} Meta_quotedbl {40 108} Meta_apostrophe {40 109} Meta_quotedbl {40 110} Meta_apostrophe {40 111} Meta_quotedbl {40 112} apostrophe {40 113} quotedbl {40 114} apostrophe {40 115} quotedbl {40 116} apostrophe {40 117} quotedbl {40 118} apostrophe {40 119} quotedbl {40 120} Meta_apostrophe {40 121} Meta_quotedbl {40 122} Meta_apostrophe {40 123} Meta_quotedbl {40 124} Meta_apostrophe {40 125} Meta_quotedbl {40 126} Meta_apostrophe {40 127} Meta_quotedbl {41 0} grave {41 1} asciitilde {41 2} grave {41 3} asciitilde {41 4} nul {41 5} Control_asciicircum {41 6} nul {41 7} Control_asciicircum {41 8} Meta_grave {41 9} Meta_asciitilde {41 10} Meta_grave {41 11} Meta_asciitilde {41 12} Meta_nul {41 13} Meta_Control_asciicircum {41 14} Meta_nul {41 15} Meta_Control_asciicircum {41 16} grave {41 17} asciitilde {41 18} grave {41 19} asciitilde {41 20} nul {41 21} Control_asciicircum {41 22} nul {41 23} Control_asciicircum {41 24} Meta_grave {41 25} Meta_asciitilde {41 26} Meta_grave {41 27} Meta_asciitilde {41 28} Meta_nul {41 29} Meta_Control_asciicircum {41 30} Meta_nul {41 31} Meta_Control_asciicircum {41 32} grave {41 33} asciitilde {41 34} grave {41 35} asciitilde {41 36} nul {41 37} Control_asciicircum {41 38} nul {41 39} Control_asciicircum {41 40} Meta_grave {41 41} Meta_asciitilde {41 42} Meta_grave {41 43} Meta_asciitilde {41 44} Meta_nul {41 45} Meta_Control_asciicircum {41 46} Meta_nul {41 47} Meta_Control_asciicircum {41 48} grave {41 49} asciitilde {41 50} grave {41 51} asciitilde {41 52} nul {41 53} Control_asciicircum {41 54} nul {41 55} Control_asciicircum {41 56} Meta_grave {41 57} Meta_asciitilde {41 58} Meta_grave {41 59} Meta_asciitilde {41 60} Meta_nul {41 61} Meta_Control_asciicircum {41 62} Meta_nul {41 63} Meta_Control_asciicircum {41 64} grave {41 65} asciitilde {41 66} grave {41 67} asciitilde {41 68} nul {41 69} Control_asciicircum {41 70} nul {41 71} Control_asciicircum {41 72} Meta_grave {41 73} Meta_asciitilde {41 74} Meta_grave {41 75} Meta_asciitilde {41 76} Meta_nul {41 77} Meta_Control_asciicircum {41 78} Meta_nul {41 79} Meta_Control_asciicircum {41 80} grave {41 81} asciitilde {41 82} grave {41 83} asciitilde {41 84} nul {41 85} Control_asciicircum {41 86} nul {41 87} Control_asciicircum {41 88} Meta_grave {41 89} Meta_asciitilde {41 90} Meta_grave {41 91} Meta_asciitilde {41 92} Meta_nul {41 93} Meta_Control_asciicircum {41 94} Meta_nul {41 95} Meta_Control_asciicircum {41 96} grave {41 97} asciitilde {41 98} grave {41 99} asciitilde {41 100} nul {41 101} Control_asciicircum {41 102} nul {41 103} Control_asciicircum {41 104} Meta_grave {41 105} Meta_asciitilde {41 106} Meta_grave {41 107} Meta_asciitilde {41 108} Meta_nul {41 109} Meta_Control_asciicircum {41 110} Meta_nul {41 111} Meta_Control_asciicircum {41 112} grave {41 113} asciitilde {41 114} grave {41 115} asciitilde {41 116} nul {41 117} Control_asciicircum {41 118} nul {41 119} Control_asciicircum {41 120} Meta_grave {41 121} Meta_asciitilde {41 122} Meta_grave {41 123} Meta_asciitilde {41 124} Meta_nul {41 125} Meta_Control_asciicircum {41 126} Meta_nul {41 127} Meta_Control_asciicircum {42 0} Shift {42 1} Shift {42 2} Shift {42 3} Shift {42 4} Shift {42 5} Shift {42 6} Shift {42 7} Shift {42 8} Shift {42 9} Shift {42 10} Shift {42 11} Shift {42 12} Shift {42 13} Shift {42 14} Shift {42 15} Shift {42 16} Shift {42 17} Shift {42 18} Shift {42 19} Shift {42 20} Shift {42 21} Shift {42 22} Shift {42 23} Shift {42 24} Shift {42 25} Shift {42 26} Shift {42 27} Shift {42 28} Shift {42 29} Shift {42 30} Shift {42 31} Shift {42 32} Shift {42 33} Shift {42 34} Shift {42 35} Shift {42 36} Shift {42 37} Shift {42 38} Shift {42 39} Shift {42 40} Shift {42 41} Shift {42 42} Shift {42 43} Shift {42 44} Shift {42 45} Shift {42 46} Shift {42 47} Shift {42 48} Shift {42 49} Shift {42 50} Shift {42 51} Shift {42 52} Shift {42 53} Shift {42 54} Shift {42 55} Shift {42 56} Shift {42 57} Shift {42 58} Shift {42 59} Shift {42 60} Shift {42 61} Shift {42 62} Shift {42 63} Shift {42 64} Shift {42 65} Shift {42 66} Shift {42 67} Shift {42 68} Shift {42 69} Shift {42 70} Shift {42 71} Shift {42 72} Shift {42 73} Shift {42 74} Shift {42 75} Shift {42 76} Shift {42 77} Shift {42 78} Shift {42 79} Shift {42 80} Shift {42 81} Shift {42 82} Shift {42 83} Shift {42 84} Shift {42 85} Shift {42 86} Shift {42 87} Shift {42 88} Shift {42 89} Shift {42 90} Shift {42 91} Shift {42 92} Shift {42 93} Shift {42 94} Shift {42 95} Shift {42 96} Shift {42 97} Shift {42 98} Shift {42 99} Shift {42 100} Shift {42 101} Shift {42 102} Shift {42 103} Shift {42 104} Shift {42 105} Shift {42 106} Shift {42 107} Shift {42 108} Shift {42 109} Shift {42 110} Shift {42 111} Shift {42 112} Shift {42 113} Shift {42 114} Shift {42 115} Shift {42 116} Shift {42 117} Shift {42 118} Shift {42 119} Shift {42 120} Shift {42 121} Shift {42 122} Shift {42 123} Shift {42 124} Shift {42 125} Shift {42 126} Shift {42 127} Shift {43 0} backslash {43 1} bar {43 2} backslash {43 3} bar {43 4} Control_backslash {43 5} Control_backslash {43 6} Control_backslash {43 7} Control_backslash {43 8} Meta_backslash {43 9} Meta_bar {43 10} Meta_backslash {43 11} Meta_bar {43 12} Meta_Control_backslash {43 13} Meta_Control_backslash {43 14} Meta_Control_backslash {43 15} Meta_Control_backslash {43 16} backslash {43 17} bar {43 18} backslash {43 19} bar {43 20} Control_backslash {43 21} Control_backslash {43 22} Control_backslash {43 23} Control_backslash {43 24} Meta_backslash {43 25} Meta_bar {43 26} Meta_backslash {43 27} Meta_bar {43 28} Meta_Control_backslash {43 29} Meta_Control_backslash {43 30} Meta_Control_backslash {43 31} Meta_Control_backslash {43 32} backslash {43 33} bar {43 34} backslash {43 35} bar {43 36} Control_backslash {43 37} Control_backslash {43 38} Control_backslash {43 39} Control_backslash {43 40} Meta_backslash {43 41} Meta_bar {43 42} Meta_backslash {43 43} Meta_bar {43 44} Meta_Control_backslash {43 45} Meta_Control_backslash {43 46} Meta_Control_backslash {43 47} Meta_Control_backslash {43 48} backslash {43 49} bar {43 50} backslash {43 51} bar {43 52} Control_backslash {43 53} Control_backslash {43 54} Control_backslash {43 55} Control_backslash {43 56} Meta_backslash {43 57} Meta_bar {43 58} Meta_backslash {43 59} Meta_bar {43 60} Meta_Control_backslash {43 61} Meta_Control_backslash {43 62} Meta_Control_backslash {43 63} Meta_Control_backslash {43 64} backslash {43 65} bar {43 66} backslash {43 67} bar {43 68} Control_backslash {43 69} Control_backslash {43 70} Control_backslash {43 71} Control_backslash {43 72} Meta_backslash {43 73} Meta_bar {43 74} Meta_backslash {43 75} Meta_bar {43 76} Meta_Control_backslash {43 77} Meta_Control_backslash {43 78} Meta_Control_backslash {43 79} Meta_Control_backslash {43 80} backslash {43 81} bar {43 82} backslash {43 83} bar {43 84} Control_backslash {43 85} Control_backslash {43 86} Control_backslash {43 87} Control_backslash {43 88} Meta_backslash {43 89} Meta_bar {43 90} Meta_backslash {43 91} Meta_bar {43 92} Meta_Control_backslash {43 93} Meta_Control_backslash {43 94} Meta_Control_backslash {43 95} Meta_Control_backslash {43 96} backslash {43 97} bar {43 98} backslash {43 99} bar {43 100} Control_backslash {43 101} Control_backslash {43 102} Control_backslash {43 103} Control_backslash {43 104} Meta_backslash {43 105} Meta_bar {43 106} Meta_backslash {43 107} Meta_bar {43 108} Meta_Control_backslash {43 109} Meta_Control_backslash {43 110} Meta_Control_backslash {43 111} Meta_Control_backslash {43 112} backslash {43 113} bar {43 114} backslash {43 115} bar {43 116} Control_backslash {43 117} Control_backslash {43 118} Control_backslash {43 119} Control_backslash {43 120} Meta_backslash {43 121} Meta_bar {43 122} Meta_backslash {43 123} Meta_bar {43 124} Meta_Control_backslash {43 125} Meta_Control_backslash {43 126} Meta_Control_backslash {43 127} Meta_Control_backslash {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} Control_z {44 5} Control_z {44 6} Control_z {44 7} Control_z {44 8} Meta_z {44 9} Meta_Z {44 10} Meta_z {44 11} Meta_Z {44 12} Meta_Control_z {44 13} Meta_Control_z {44 14} Meta_Control_z {44 15} Meta_Control_z {44 16} z {44 17} Z {44 18} z {44 19} Z {44 20} Control_z {44 21} Control_z {44 22} Control_z {44 23} Control_z {44 24} Meta_z {44 25} Meta_Z {44 26} Meta_z {44 27} Meta_Z {44 28} Meta_Control_z {44 29} Meta_Control_z {44 30} Meta_Control_z {44 31} Meta_Control_z {44 32} z {44 33} Z {44 34} z {44 35} Z {44 36} Control_z {44 37} Control_z {44 38} Control_z {44 39} Control_z {44 40} Meta_z {44 41} Meta_Z {44 42} Meta_z {44 43} Meta_Z {44 44} Meta_Control_z {44 45} Meta_Control_z {44 46} Meta_Control_z {44 47} Meta_Control_z {44 48} z {44 49} Z {44 50} z {44 51} Z {44 52} Control_z {44 53} Control_z {44 54} Control_z {44 55} Control_z {44 56} Meta_z {44 57} Meta_Z {44 58} Meta_z {44 59} Meta_Z {44 60} Meta_Control_z {44 61} Meta_Control_z {44 62} Meta_Control_z {44 63} Meta_Control_z {44 64} Z {44 65} z {44 66} Z {44 67} z {44 68} Control_z {44 69} Control_z {44 70} Control_z {44 71} Control_z {44 72} Meta_z {44 73} Meta_Z {44 74} Meta_z {44 75} Meta_Z {44 76} Meta_Control_z {44 77} Meta_Control_z {44 78} Meta_Control_z {44 79} Meta_Control_z {44 80} Z {44 81} z {44 82} Z {44 83} z {44 84} Control_z {44 85} Control_z {44 86} Control_z {44 87} Control_z {44 88} Meta_z {44 89} Meta_Z {44 90} Meta_z {44 91} Meta_Z {44 92} Meta_Control_z {44 93} Meta_Control_z {44 94} Meta_Control_z {44 95} Meta_Control_z {44 96} Z {44 97} z {44 98} Z {44 99} z {44 100} Control_z {44 101} Control_z {44 102} Control_z {44 103} Control_z {44 104} Meta_z {44 105} Meta_Z {44 106} Meta_z {44 107} Meta_Z {44 108} Meta_Control_z {44 109} Meta_Control_z {44 110} Meta_Control_z {44 111} Meta_Control_z {44 112} Z {44 113} z {44 114} Z {44 115} z {44 116} Control_z {44 117} Control_z {44 118} Control_z {44 119} Control_z {44 120} Meta_z {44 121} Meta_Z {44 122} Meta_z {44 123} Meta_Z {44 124} Meta_Control_z {44 125} Meta_Control_z {44 126} Meta_Control_z {44 127} Meta_Control_z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} Control_x {45 5} Control_x {45 6} Control_x {45 7} Control_x {45 8} Meta_x {45 9} Meta_X {45 10} Meta_x {45 11} Meta_X {45 12} Meta_Control_x {45 13} Meta_Control_x {45 14} Meta_Control_x {45 15} Meta_Control_x {45 16} x {45 17} X {45 18} x {45 19} X {45 20} Control_x {45 21} Control_x {45 22} Control_x {45 23} Control_x {45 24} Meta_x {45 25} Meta_X {45 26} Meta_x {45 27} Meta_X {45 28} Meta_Control_x {45 29} Meta_Control_x {45 30} Meta_Control_x {45 31} Meta_Control_x {45 32} x {45 33} X {45 34} x {45 35} X {45 36} Control_x {45 37} Control_x {45 38} Control_x {45 39} Control_x {45 40} Meta_x {45 41} Meta_X {45 42} Meta_x {45 43} Meta_X {45 44} Meta_Control_x {45 45} Meta_Control_x {45 46} Meta_Control_x {45 47} Meta_Control_x {45 48} x {45 49} X {45 50} x {45 51} X {45 52} Control_x {45 53} Control_x {45 54} Control_x {45 55} Control_x {45 56} Meta_x {45 57} Meta_X {45 58} Meta_x {45 59} Meta_X {45 60} Meta_Control_x {45 61} Meta_Control_x {45 62} Meta_Control_x {45 63} Meta_Control_x {45 64} X {45 65} x {45 66} X {45 67} x {45 68} Control_x {45 69} Control_x {45 70} Control_x {45 71} Control_x {45 72} Meta_x {45 73} Meta_X {45 74} Meta_x {45 75} Meta_X {45 76} Meta_Control_x {45 77} Meta_Control_x {45 78} Meta_Control_x {45 79} Meta_Control_x {45 80} X {45 81} x {45 82} X {45 83} x {45 84} Control_x {45 85} Control_x {45 86} Control_x {45 87} Control_x {45 88} Meta_x {45 89} Meta_X {45 90} Meta_x {45 91} Meta_X {45 92} Meta_Control_x {45 93} Meta_Control_x {45 94} Meta_Control_x {45 95} Meta_Control_x {45 96} X {45 97} x {45 98} X {45 99} x {45 100} Control_x {45 101} Control_x {45 102} Control_x {45 103} Control_x {45 104} Meta_x {45 105} Meta_X {45 106} Meta_x {45 107} Meta_X {45 108} Meta_Control_x {45 109} Meta_Control_x {45 110} Meta_Control_x {45 111} Meta_Control_x {45 112} X {45 113} x {45 114} X {45 115} x {45 116} Control_x {45 117} Control_x {45 118} Control_x {45 119} Control_x {45 120} Meta_x {45 121} Meta_X {45 122} Meta_x {45 123} Meta_X {45 124} Meta_Control_x {45 125} Meta_Control_x {45 126} Meta_Control_x {45 127} Meta_Control_x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} Control_c {46 5} Control_c {46 6} Control_c {46 7} Control_c {46 8} Meta_c {46 9} Meta_C {46 10} Meta_c {46 11} Meta_C {46 12} Meta_Control_c {46 13} Meta_Control_c {46 14} Meta_Control_c {46 15} Meta_Control_c {46 16} c {46 17} C {46 18} c {46 19} C {46 20} Control_c {46 21} Control_c {46 22} Control_c {46 23} Control_c {46 24} Meta_c {46 25} Meta_C {46 26} Meta_c {46 27} Meta_C {46 28} Meta_Control_c {46 29} Meta_Control_c {46 30} Meta_Control_c {46 31} Meta_Control_c {46 32} c {46 33} C {46 34} c {46 35} C {46 36} Control_c {46 37} Control_c {46 38} Control_c {46 39} Control_c {46 40} Meta_c {46 41} Meta_C {46 42} Meta_c {46 43} Meta_C {46 44} Meta_Control_c {46 45} Meta_Control_c {46 46} Meta_Control_c {46 47} Meta_Control_c {46 48} c {46 49} C {46 50} c {46 51} C {46 52} Control_c {46 53} Control_c {46 54} Control_c {46 55} Control_c {46 56} Meta_c {46 57} Meta_C {46 58} Meta_c {46 59} Meta_C {46 60} Meta_Control_c {46 61} Meta_Control_c {46 62} Meta_Control_c {46 63} Meta_Control_c {46 64} C {46 65} c {46 66} C {46 67} c {46 68} Control_c {46 69} Control_c {46 70} Control_c {46 71} Control_c {46 72} Meta_c {46 73} Meta_C {46 74} Meta_c {46 75} Meta_C {46 76} Meta_Control_c {46 77} Meta_Control_c {46 78} Meta_Control_c {46 79} Meta_Control_c {46 80} C {46 81} c {46 82} C {46 83} c {46 84} Control_c {46 85} Control_c {46 86} Control_c {46 87} Control_c {46 88} Meta_c {46 89} Meta_C {46 90} Meta_c {46 91} Meta_C {46 92} Meta_Control_c {46 93} Meta_Control_c {46 94} Meta_Control_c {46 95} Meta_Control_c {46 96} C {46 97} c {46 98} C {46 99} c {46 100} Control_c {46 101} Control_c {46 102} Control_c {46 103} Control_c {46 104} Meta_c {46 105} Meta_C {46 106} Meta_c {46 107} Meta_C {46 108} Meta_Control_c {46 109} Meta_Control_c {46 110} Meta_Control_c {46 111} Meta_Control_c {46 112} C {46 113} c {46 114} C {46 115} c {46 116} Control_c {46 117} Control_c {46 118} Control_c {46 119} Control_c {46 120} Meta_c {46 121} Meta_C {46 122} Meta_c {46 123} Meta_C {46 124} Meta_Control_c {46 125} Meta_Control_c {46 126} Meta_Control_c {46 127} Meta_Control_c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} Control_v {47 5} Control_v {47 6} Control_v {47 7} Control_v {47 8} Meta_v {47 9} Meta_V {47 10} Meta_v {47 11} Meta_V {47 12} Meta_Control_v {47 13} Meta_Control_v {47 14} Meta_Control_v {47 15} Meta_Control_v {47 16} v {47 17} V {47 18} v {47 19} V {47 20} Control_v {47 21} Control_v {47 22} Control_v {47 23} Control_v {47 24} Meta_v {47 25} Meta_V {47 26} Meta_v {47 27} Meta_V {47 28} Meta_Control_v {47 29} Meta_Control_v {47 30} Meta_Control_v {47 31} Meta_Control_v {47 32} v {47 33} V {47 34} v {47 35} V {47 36} Control_v {47 37} Control_v {47 38} Control_v {47 39} Control_v {47 40} Meta_v {47 41} Meta_V {47 42} Meta_v {47 43} Meta_V {47 44} Meta_Control_v {47 45} Meta_Control_v {47 46} Meta_Control_v {47 47} Meta_Control_v {47 48} v {47 49} V {47 50} v {47 51} V {47 52} Control_v {47 53} Control_v {47 54} Control_v {47 55} Control_v {47 56} Meta_v {47 57} Meta_V {47 58} Meta_v {47 59} Meta_V {47 60} Meta_Control_v {47 61} Meta_Control_v {47 62} Meta_Control_v {47 63} Meta_Control_v {47 64} V {47 65} v {47 66} V {47 67} v {47 68} Control_v {47 69} Control_v {47 70} Control_v {47 71} Control_v {47 72} Meta_v {47 73} Meta_V {47 74} Meta_v {47 75} Meta_V {47 76} Meta_Control_v {47 77} Meta_Control_v {47 78} Meta_Control_v {47 79} Meta_Control_v {47 80} V {47 81} v {47 82} V {47 83} v {47 84} Control_v {47 85} Control_v {47 86} Control_v {47 87} Control_v {47 88} Meta_v {47 89} Meta_V {47 90} Meta_v {47 91} Meta_V {47 92} Meta_Control_v {47 93} Meta_Control_v {47 94} Meta_Control_v {47 95} Meta_Control_v {47 96} V {47 97} v {47 98} V {47 99} v {47 100} Control_v {47 101} Control_v {47 102} Control_v {47 103} Control_v {47 104} Meta_v {47 105} Meta_V {47 106} Meta_v {47 107} Meta_V {47 108} Meta_Control_v {47 109} Meta_Control_v {47 110} Meta_Control_v {47 111} Meta_Control_v {47 112} V {47 113} v {47 114} V {47 115} v {47 116} Control_v {47 117} Control_v {47 118} Control_v {47 119} Control_v {47 120} Meta_v {47 121} Meta_V {47 122} Meta_v {47 123} Meta_V {47 124} Meta_Control_v {47 125} Meta_Control_v {47 126} Meta_Control_v {47 127} Meta_Control_v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} Control_b {48 5} Control_b {48 6} Control_b {48 7} Control_b {48 8} Meta_b {48 9} Meta_B {48 10} Meta_b {48 11} Meta_B {48 12} Meta_Control_b {48 13} Meta_Control_b {48 14} Meta_Control_b {48 15} Meta_Control_b {48 16} b {48 17} B {48 18} b {48 19} B {48 20} Control_b {48 21} Control_b {48 22} Control_b {48 23} Control_b {48 24} Meta_b {48 25} Meta_B {48 26} Meta_b {48 27} Meta_B {48 28} Meta_Control_b {48 29} Meta_Control_b {48 30} Meta_Control_b {48 31} Meta_Control_b {48 32} b {48 33} B {48 34} b {48 35} B {48 36} Control_b {48 37} Control_b {48 38} Control_b {48 39} Control_b {48 40} Meta_b {48 41} Meta_B {48 42} Meta_b {48 43} Meta_B {48 44} Meta_Control_b {48 45} Meta_Control_b {48 46} Meta_Control_b {48 47} Meta_Control_b {48 48} b {48 49} B {48 50} b {48 51} B {48 52} Control_b {48 53} Control_b {48 54} Control_b {48 55} Control_b {48 56} Meta_b {48 57} Meta_B {48 58} Meta_b {48 59} Meta_B {48 60} Meta_Control_b {48 61} Meta_Control_b {48 62} Meta_Control_b {48 63} Meta_Control_b {48 64} B {48 65} b {48 66} B {48 67} b {48 68} Control_b {48 69} Control_b {48 70} Control_b {48 71} Control_b {48 72} Meta_b {48 73} Meta_B {48 74} Meta_b {48 75} Meta_B {48 76} Meta_Control_b {48 77} Meta_Control_b {48 78} Meta_Control_b {48 79} Meta_Control_b {48 80} B {48 81} b {48 82} B {48 83} b {48 84} Control_b {48 85} Control_b {48 86} Control_b {48 87} Control_b {48 88} Meta_b {48 89} Meta_B {48 90} Meta_b {48 91} Meta_B {48 92} Meta_Control_b {48 93} Meta_Control_b {48 94} Meta_Control_b {48 95} Meta_Control_b {48 96} B {48 97} b {48 98} B {48 99} b {48 100} Control_b {48 101} Control_b {48 102} Control_b {48 103} Control_b {48 104} Meta_b {48 105} Meta_B {48 106} Meta_b {48 107} Meta_B {48 108} Meta_Control_b {48 109} Meta_Control_b {48 110} Meta_Control_b {48 111} Meta_Control_b {48 112} B {48 113} b {48 114} B {48 115} b {48 116} Control_b {48 117} Control_b {48 118} Control_b {48 119} Control_b {48 120} Meta_b {48 121} Meta_B {48 122} Meta_b {48 123} Meta_B {48 124} Meta_Control_b {48 125} Meta_Control_b {48 126} Meta_Control_b {48 127} Meta_Control_b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} Control_n {49 5} Control_n {49 6} Control_n {49 7} Control_n {49 8} Meta_n {49 9} Meta_N {49 10} Meta_n {49 11} Meta_N {49 12} Meta_Control_n {49 13} Meta_Control_n {49 14} Meta_Control_n {49 15} Meta_Control_n {49 16} n {49 17} N {49 18} n {49 19} N {49 20} Control_n {49 21} Control_n {49 22} Control_n {49 23} Control_n {49 24} Meta_n {49 25} Meta_N {49 26} Meta_n {49 27} Meta_N {49 28} Meta_Control_n {49 29} Meta_Control_n {49 30} Meta_Control_n {49 31} Meta_Control_n {49 32} n {49 33} N {49 34} n {49 35} N {49 36} Control_n {49 37} Control_n {49 38} Control_n {49 39} Control_n {49 40} Meta_n {49 41} Meta_N {49 42} Meta_n {49 43} Meta_N {49 44} Meta_Control_n {49 45} Meta_Control_n {49 46} Meta_Control_n {49 47} Meta_Control_n {49 48} n {49 49} N {49 50} n {49 51} N {49 52} Control_n {49 53} Control_n {49 54} Control_n {49 55} Control_n {49 56} Meta_n {49 57} Meta_N {49 58} Meta_n {49 59} Meta_N {49 60} Meta_Control_n {49 61} Meta_Control_n {49 62} Meta_Control_n {49 63} Meta_Control_n {49 64} N {49 65} n {49 66} N {49 67} n {49 68} Control_n {49 69} Control_n {49 70} Control_n {49 71} Control_n {49 72} Meta_n {49 73} Meta_N {49 74} Meta_n {49 75} Meta_N {49 76} Meta_Control_n {49 77} Meta_Control_n {49 78} Meta_Control_n {49 79} Meta_Control_n {49 80} N {49 81} n {49 82} N {49 83} n {49 84} Control_n {49 85} Control_n {49 86} Control_n {49 87} Control_n {49 88} Meta_n {49 89} Meta_N {49 90} Meta_n {49 91} Meta_N {49 92} Meta_Control_n {49 93} Meta_Control_n {49 94} Meta_Control_n {49 95} Meta_Control_n {49 96} N {49 97} n {49 98} N {49 99} n {49 100} Control_n {49 101} Control_n {49 102} Control_n {49 103} Control_n {49 104} Meta_n {49 105} Meta_N {49 106} Meta_n {49 107} Meta_N {49 108} Meta_Control_n {49 109} Meta_Control_n {49 110} Meta_Control_n {49 111} Meta_Control_n {49 112} N {49 113} n {49 114} N {49 115} n {49 116} Control_n {49 117} Control_n {49 118} Control_n {49 119} Control_n {49 120} Meta_n {49 121} Meta_N {49 122} Meta_n {49 123} Meta_N {49 124} Meta_Control_n {49 125} Meta_Control_n {49 126} Meta_Control_n {49 127} Meta_Control_n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} Return {50 5} Return {50 6} Return {50 7} Return {50 8} Meta_m {50 9} Meta_M {50 10} Meta_m {50 11} Meta_M {50 12} Meta_Control_m {50 13} Meta_Control_m {50 14} Meta_Control_m {50 15} Meta_Control_m {50 16} m {50 17} M {50 18} m {50 19} M {50 20} Return {50 21} Return {50 22} Return {50 23} Return {50 24} Meta_m {50 25} Meta_M {50 26} Meta_m {50 27} Meta_M {50 28} Meta_Control_m {50 29} Meta_Control_m {50 30} Meta_Control_m {50 31} Meta_Control_m {50 32} m {50 33} M {50 34} m {50 35} M {50 36} Return {50 37} Return {50 38} Return {50 39} Return {50 40} Meta_m {50 41} Meta_M {50 42} Meta_m {50 43} Meta_M {50 44} Meta_Control_m {50 45} Meta_Control_m {50 46} Meta_Control_m {50 47} Meta_Control_m {50 48} m {50 49} M {50 50} m {50 51} M {50 52} Return {50 53} Return {50 54} Return {50 55} Return {50 56} Meta_m {50 57} Meta_M {50 58} Meta_m {50 59} Meta_M {50 60} Meta_Control_m {50 61} Meta_Control_m {50 62} Meta_Control_m {50 63} Meta_Control_m {50 64} M {50 65} m {50 66} M {50 67} m {50 68} Return {50 69} Return {50 70} Return {50 71} Return {50 72} Meta_m {50 73} Meta_M {50 74} Meta_m {50 75} Meta_M {50 76} Meta_Control_m {50 77} Meta_Control_m {50 78} Meta_Control_m {50 79} Meta_Control_m {50 80} M {50 81} m {50 82} M {50 83} m {50 84} Return {50 85} Return {50 86} Return {50 87} Return {50 88} Meta_m {50 89} Meta_M {50 90} Meta_m {50 91} Meta_M {50 92} Meta_Control_m {50 93} Meta_Control_m {50 94} Meta_Control_m {50 95} Meta_Control_m {50 96} M {50 97} m {50 98} M {50 99} m {50 100} Return {50 101} Return {50 102} Return {50 103} Return {50 104} Meta_m {50 105} Meta_M {50 106} Meta_m {50 107} Meta_M {50 108} Meta_Control_m {50 109} Meta_Control_m {50 110} Meta_Control_m {50 111} Meta_Control_m {50 112} M {50 113} m {50 114} M {50 115} m {50 116} Return {50 117} Return {50 118} Return {50 119} Return {50 120} Meta_m {50 121} Meta_M {50 122} Meta_m {50 123} Meta_M {50 124} Meta_Control_m {50 125} Meta_Control_m {50 126} Meta_Control_m {50 127} Meta_Control_m {51 0} comma {51 1} less {51 2} comma {51 3} less {51 4} comma {51 5} less {51 6} comma {51 7} less {51 8} Meta_comma {51 9} Meta_less {51 10} Meta_comma {51 11} Meta_less {51 12} Meta_comma {51 13} Meta_less {51 14} Meta_comma {51 15} Meta_less {51 16} comma {51 17} less {51 18} comma {51 19} less {51 20} comma {51 21} less {51 22} comma {51 23} less {51 24} Meta_comma {51 25} Meta_less {51 26} Meta_comma {51 27} Meta_less {51 28} Meta_comma {51 29} Meta_less {51 30} Meta_comma {51 31} Meta_less {51 32} comma {51 33} less {51 34} comma {51 35} less {51 36} comma {51 37} less {51 38} comma {51 39} less {51 40} Meta_comma {51 41} Meta_less {51 42} Meta_comma {51 43} Meta_less {51 44} Meta_comma {51 45} Meta_less {51 46} Meta_comma {51 47} Meta_less {51 48} comma {51 49} less {51 50} comma {51 51} less {51 52} comma {51 53} less {51 54} comma {51 55} less {51 56} Meta_comma {51 57} Meta_less {51 58} Meta_comma {51 59} Meta_less {51 60} Meta_comma {51 61} Meta_less {51 62} Meta_comma {51 63} Meta_less {51 64} comma {51 65} less {51 66} comma {51 67} less {51 68} comma {51 69} less {51 70} comma {51 71} less {51 72} Meta_comma {51 73} Meta_less {51 74} Meta_comma {51 75} Meta_less {51 76} Meta_comma {51 77} Meta_less {51 78} Meta_comma {51 79} Meta_less {51 80} comma {51 81} less {51 82} comma {51 83} less {51 84} comma {51 85} less {51 86} comma {51 87} less {51 88} Meta_comma {51 89} Meta_less {51 90} Meta_comma {51 91} Meta_less {51 92} Meta_comma {51 93} Meta_less {51 94} Meta_comma {51 95} Meta_less {51 96} comma {51 97} less {51 98} comma {51 99} less {51 100} comma {51 101} less {51 102} comma {51 103} less {51 104} Meta_comma {51 105} Meta_less {51 106} Meta_comma {51 107} Meta_less {51 108} Meta_comma {51 109} Meta_less {51 110} Meta_comma {51 111} Meta_less {51 112} comma {51 113} less {51 114} comma {51 115} less {51 116} comma {51 117} less {51 118} comma {51 119} less {51 120} Meta_comma {51 121} Meta_less {51 122} Meta_comma {51 123} Meta_less {51 124} Meta_comma {51 125} Meta_less {51 126} Meta_comma {51 127} Meta_less {52 0} period {52 1} greater {52 2} period {52 3} greater {52 4} Compose {52 5} Compose {52 6} Compose {52 7} Compose {52 8} Meta_period {52 9} Meta_greater {52 10} Meta_period {52 11} Meta_greater {52 12} Compose {52 13} Compose {52 14} Compose {52 15} Compose {52 16} period {52 17} greater {52 18} period {52 19} greater {52 20} Compose {52 21} Compose {52 22} Compose {52 23} Compose {52 24} Meta_period {52 25} Meta_greater {52 26} Meta_period {52 27} Meta_greater {52 28} Compose {52 29} Compose {52 30} Compose {52 31} Compose {52 32} period {52 33} greater {52 34} period {52 35} greater {52 36} Compose {52 37} Compose {52 38} Compose {52 39} Compose {52 40} Meta_period {52 41} Meta_greater {52 42} Meta_period {52 43} Meta_greater {52 44} Compose {52 45} Compose {52 46} Compose {52 47} Compose {52 48} period {52 49} greater {52 50} period {52 51} greater {52 52} Compose {52 53} Compose {52 54} Compose {52 55} Compose {52 56} Meta_period {52 57} Meta_greater {52 58} Meta_period {52 59} Meta_greater {52 60} Compose {52 61} Compose {52 62} Compose {52 63} Compose {52 64} period {52 65} greater {52 66} period {52 67} greater {52 68} Compose {52 69} Compose {52 70} Compose {52 71} Compose {52 72} Meta_period {52 73} Meta_greater {52 74} Meta_period {52 75} Meta_greater {52 76} Compose {52 77} Compose {52 78} Compose {52 79} Compose {52 80} period {52 81} greater {52 82} period {52 83} greater {52 84} Compose {52 85} Compose {52 86} Compose {52 87} Compose {52 88} Meta_period {52 89} Meta_greater {52 90} Meta_period {52 91} Meta_greater {52 92} Compose {52 93} Compose {52 94} Compose {52 95} Compose {52 96} period {52 97} greater {52 98} period {52 99} greater {52 100} Compose {52 101} Compose {52 102} Compose {52 103} Compose {52 104} Meta_period {52 105} Meta_greater {52 106} Meta_period {52 107} Meta_greater {52 108} Compose {52 109} Compose {52 110} Compose {52 111} Compose {52 112} period {52 113} greater {52 114} period {52 115} greater {52 116} Compose {52 117} Compose {52 118} Compose {52 119} Compose {52 120} Meta_period {52 121} Meta_greater {52 122} Meta_period {52 123} Meta_greater {52 124} Compose {52 125} Compose {52 126} Compose {52 127} Compose {53 0} slash {53 1} question {53 2} slash {53 3} question {53 4} Delete {53 5} Delete {53 6} Delete {53 7} Delete {53 8} Meta_slash {53 9} Meta_question {53 10} Meta_slash {53 11} Meta_question {53 12} Meta_Delete {53 13} Meta_Delete {53 14} Meta_Delete {53 15} Meta_Delete {53 16} slash {53 17} question {53 18} slash {53 19} question {53 20} Delete {53 21} Delete {53 22} Delete {53 23} Delete {53 24} Meta_slash {53 25} Meta_question {53 26} Meta_slash {53 27} Meta_question {53 28} Meta_Delete {53 29} Meta_Delete {53 30} Meta_Delete {53 31} Meta_Delete {53 32} slash {53 33} question {53 34} slash {53 35} question {53 36} Delete {53 37} Delete {53 38} Delete {53 39} Delete {53 40} Meta_slash {53 41} Meta_question {53 42} Meta_slash {53 43} Meta_question {53 44} Meta_Delete {53 45} Meta_Delete {53 46} Meta_Delete {53 47} Meta_Delete {53 48} slash {53 49} question {53 50} slash {53 51} question {53 52} Delete {53 53} Delete {53 54} Delete {53 55} Delete {53 56} Meta_slash {53 57} Meta_question {53 58} Meta_slash {53 59} Meta_question {53 60} Meta_Delete {53 61} Meta_Delete {53 62} Meta_Delete {53 63} Meta_Delete {53 64} slash {53 65} question {53 66} slash {53 67} question {53 68} Delete {53 69} Delete {53 70} Delete {53 71} Delete {53 72} Meta_slash {53 73} Meta_question {53 74} Meta_slash {53 75} Meta_question {53 76} Meta_Delete {53 77} Meta_Delete {53 78} Meta_Delete {53 79} Meta_Delete {53 80} slash {53 81} question {53 82} slash {53 83} question {53 84} Delete {53 85} Delete {53 86} Delete {53 87} Delete {53 88} Meta_slash {53 89} Meta_question {53 90} Meta_slash {53 91} Meta_question {53 92} Meta_Delete {53 93} Meta_Delete {53 94} Meta_Delete {53 95} Meta_Delete {53 96} slash {53 97} question {53 98} slash {53 99} question {53 100} Delete {53 101} Delete {53 102} Delete {53 103} Delete {53 104} Meta_slash {53 105} Meta_question {53 106} Meta_slash {53 107} Meta_question {53 108} Meta_Delete {53 109} Meta_Delete {53 110} Meta_Delete {53 111} Meta_Delete {53 112} slash {53 113} question {53 114} slash {53 115} question {53 116} Delete {53 117} Delete {53 118} Delete {53 119} Delete {53 120} Meta_slash {53 121} Meta_question {53 122} Meta_slash {53 123} Meta_question {53 124} Meta_Delete {53 125} Meta_Delete {53 126} Meta_Delete {53 127} Meta_Delete {54 0} Shift {54 1} Shift {54 2} Shift {54 3} Shift {54 4} Shift {54 5} Shift {54 6} Shift {54 7} Shift {54 8} Shift {54 9} Shift {54 10} Shift {54 11} Shift {54 12} Shift {54 13} Shift {54 14} Shift {54 15} Shift {54 16} Shift {54 17} Shift {54 18} Shift {54 19} Shift {54 20} Shift {54 21} Shift {54 22} Shift {54 23} Shift {54 24} Shift {54 25} Shift {54 26} Shift {54 27} Shift {54 28} Shift {54 29} Shift {54 30} Shift {54 31} Shift {54 32} Shift {54 33} Shift {54 34} Shift {54 35} Shift {54 36} Shift {54 37} Shift {54 38} Shift {54 39} Shift {54 40} Shift {54 41} Shift {54 42} Shift {54 43} Shift {54 44} Shift {54 45} Shift {54 46} Shift {54 47} Shift {54 48} Shift {54 49} Shift {54 50} Shift {54 51} Shift {54 52} Shift {54 53} Shift {54 54} Shift {54 55} Shift {54 56} Shift {54 57} Shift {54 58} Shift {54 59} Shift {54 60} Shift {54 61} Shift {54 62} Shift {54 63} Shift {54 64} Shift {54 65} Shift {54 66} Shift {54 67} Shift {54 68} Shift {54 69} Shift {54 70} Shift {54 71} Shift {54 72} Shift {54 73} Shift {54 74} Shift {54 75} Shift {54 76} Shift {54 77} Shift {54 78} Shift {54 79} Shift {54 80} Shift {54 81} Shift {54 82} Shift {54 83} Shift {54 84} Shift {54 85} Shift {54 86} Shift {54 87} Shift {54 88} Shift {54 89} Shift {54 90} Shift {54 91} Shift {54 92} Shift {54 93} Shift {54 94} Shift {54 95} Shift {54 96} Shift {54 97} Shift {54 98} Shift {54 99} Shift {54 100} Shift {54 101} Shift {54 102} Shift {54 103} Shift {54 104} Shift {54 105} Shift {54 106} Shift {54 107} Shift {54 108} Shift {54 109} Shift {54 110} Shift {54 111} Shift {54 112} Shift {54 113} Shift {54 114} Shift {54 115} Shift {54 116} Shift {54 117} Shift {54 118} Shift {54 119} Shift {54 120} Shift {54 121} Shift {54 122} Shift {54 123} Shift {54 124} Shift {54 125} Shift {54 126} Shift {54 127} Shift {55 0} KP_Multiply {55 1} KP_Multiply {55 2} Hex_C {55 3} KP_Multiply {55 4} KP_Multiply {55 5} KP_Multiply {55 6} KP_Multiply {55 7} KP_Multiply {55 8} KP_Multiply {55 9} Hex_C {55 10} KP_Multiply {55 11} KP_Multiply {55 12} KP_Multiply {55 13} KP_Multiply {55 14} KP_Multiply {55 15} KP_Multiply {55 16} KP_Multiply {55 17} KP_Multiply {55 18} Hex_C {55 19} KP_Multiply {55 20} KP_Multiply {55 21} KP_Multiply {55 22} KP_Multiply {55 23} KP_Multiply {55 24} KP_Multiply {55 25} Hex_C {55 26} KP_Multiply {55 27} KP_Multiply {55 28} KP_Multiply {55 29} KP_Multiply {55 30} KP_Multiply {55 31} KP_Multiply {55 32} KP_Multiply {55 33} KP_Multiply {55 34} Hex_C {55 35} KP_Multiply {55 36} KP_Multiply {55 37} KP_Multiply {55 38} KP_Multiply {55 39} KP_Multiply {55 40} KP_Multiply {55 41} Hex_C {55 42} KP_Multiply {55 43} KP_Multiply {55 44} KP_Multiply {55 45} KP_Multiply {55 46} KP_Multiply {55 47} KP_Multiply {55 48} KP_Multiply {55 49} KP_Multiply {55 50} Hex_C {55 51} KP_Multiply {55 52} KP_Multiply {55 53} KP_Multiply {55 54} KP_Multiply {55 55} KP_Multiply {55 56} KP_Multiply {55 57} Hex_C {55 58} KP_Multiply {55 59} KP_Multiply {55 60} KP_Multiply {55 61} KP_Multiply {55 62} KP_Multiply {55 63} KP_Multiply {55 64} KP_Multiply {55 65} KP_Multiply {55 66} Hex_C {55 67} KP_Multiply {55 68} KP_Multiply {55 69} KP_Multiply {55 70} KP_Multiply {55 71} KP_Multiply {55 72} KP_Multiply {55 73} Hex_C {55 74} KP_Multiply {55 75} KP_Multiply {55 76} KP_Multiply {55 77} KP_Multiply {55 78} KP_Multiply {55 79} KP_Multiply {55 80} KP_Multiply {55 81} KP_Multiply {55 82} Hex_C {55 83} KP_Multiply {55 84} KP_Multiply {55 85} KP_Multiply {55 86} KP_Multiply {55 87} KP_Multiply {55 88} KP_Multiply {55 89} Hex_C {55 90} KP_Multiply {55 91} KP_Multiply {55 92} KP_Multiply {55 93} KP_Multiply {55 94} KP_Multiply {55 95} KP_Multiply {55 96} KP_Multiply {55 97} KP_Multiply {55 98} Hex_C {55 99} KP_Multiply {55 100} KP_Multiply {55 101} KP_Multiply {55 102} KP_Multiply {55 103} KP_Multiply {55 104} KP_Multiply {55 105} Hex_C {55 106} KP_Multiply {55 107} KP_Multiply {55 108} KP_Multiply {55 109} KP_Multiply {55 110} KP_Multiply {55 111} KP_Multiply {55 112} KP_Multiply {55 113} KP_Multiply {55 114} Hex_C {55 115} KP_Multiply {55 116} KP_Multiply {55 117} KP_Multiply {55 118} KP_Multiply {55 119} KP_Multiply {55 120} KP_Multiply {55 121} Hex_C {55 122} KP_Multiply {55 123} KP_Multiply {55 124} KP_Multiply {55 125} KP_Multiply {55 126} KP_Multiply {55 127} KP_Multiply {56 0} Alt {56 1} Alt {56 2} Alt {56 3} Alt {56 4} Alt {56 5} Alt {56 6} Alt {56 7} Alt {56 8} Alt {56 9} Alt {56 10} Alt {56 11} Alt {56 12} Alt {56 13} Alt {56 14} Alt {56 15} Alt {56 16} Alt {56 17} Alt {56 18} Alt {56 19} Alt {56 20} Alt {56 21} Alt {56 22} Alt {56 23} Alt {56 24} Alt {56 25} Alt {56 26} Alt {56 27} Alt {56 28} Alt {56 29} Alt {56 30} Alt {56 31} Alt {56 32} Alt {56 33} Alt {56 34} Alt {56 35} Alt {56 36} Alt {56 37} Alt {56 38} Alt {56 39} Alt {56 40} Alt {56 41} Alt {56 42} Alt {56 43} Alt {56 44} Alt {56 45} Alt {56 46} Alt {56 47} Alt {56 48} Alt {56 49} Alt {56 50} Alt {56 51} Alt {56 52} Alt {56 53} Alt {56 54} Alt {56 55} Alt {56 56} Alt {56 57} Alt {56 58} Alt {56 59} Alt {56 60} Alt {56 61} Alt {56 62} Alt {56 63} Alt {56 64} Alt {56 65} Alt {56 66} Alt {56 67} Alt {56 68} Alt {56 69} Alt {56 70} Alt {56 71} Alt {56 72} Alt {56 73} Alt {56 74} Alt {56 75} Alt {56 76} Alt {56 77} Alt {56 78} Alt {56 79} Alt {56 80} Alt {56 81} Alt {56 82} Alt {56 83} Alt {56 84} Alt {56 85} Alt {56 86} Alt {56 87} Alt {56 88} Alt {56 89} Alt {56 90} Alt {56 91} Alt {56 92} Alt {56 93} Alt {56 94} Alt {56 95} Alt {56 96} Alt {56 97} Alt {56 98} Alt {56 99} Alt {56 100} Alt {56 101} Alt {56 102} Alt {56 103} Alt {56 104} Alt {56 105} Alt {56 106} Alt {56 107} Alt {56 108} Alt {56 109} Alt {56 110} Alt {56 111} Alt {56 112} Alt {56 113} Alt {56 114} Alt {56 115} Alt {56 116} Alt {56 117} Alt {56 118} Alt {56 119} Alt {56 120} Alt {56 121} Alt {56 122} Alt {56 123} Alt {56 124} Alt {56 125} Alt {56 126} Alt {56 127} Alt {57 0} space {57 1} space {57 2} space {57 3} space {57 4} nul {57 5} nul {57 6} nul {57 7} nul {57 8} Meta_space {57 9} Meta_space {57 10} Meta_space {57 11} Meta_space {57 12} Meta_nul {57 13} Meta_nul {57 14} Meta_nul {57 15} Meta_nul {57 16} space {57 17} space {57 18} space {57 19} space {57 20} nul {57 21} nul {57 22} nul {57 23} nul {57 24} Meta_space {57 25} Meta_space {57 26} Meta_space {57 27} Meta_space {57 28} Meta_nul {57 29} Meta_nul {57 30} Meta_nul {57 31} Meta_nul {57 32} space {57 33} space {57 34} space {57 35} space {57 36} nul {57 37} nul {57 38} nul {57 39} nul {57 40} Meta_space {57 41} Meta_space {57 42} Meta_space {57 43} Meta_space {57 44} Meta_nul {57 45} Meta_nul {57 46} Meta_nul {57 47} Meta_nul {57 48} space {57 49} space {57 50} space {57 51} space {57 52} nul {57 53} nul {57 54} nul {57 55} nul {57 56} Meta_space {57 57} Meta_space {57 58} Meta_space {57 59} Meta_space {57 60} Meta_nul {57 61} Meta_nul {57 62} Meta_nul {57 63} Meta_nul {57 64} space {57 65} space {57 66} space {57 67} space {57 68} nul {57 69} nul {57 70} nul {57 71} nul {57 72} Meta_space {57 73} Meta_space {57 74} Meta_space {57 75} Meta_space {57 76} Meta_nul {57 77} Meta_nul {57 78} Meta_nul {57 79} Meta_nul {57 80} space {57 81} space {57 82} space {57 83} space {57 84} nul {57 85} nul {57 86} nul {57 87} nul {57 88} Meta_space {57 89} Meta_space {57 90} Meta_space {57 91} Meta_space {57 92} Meta_nul {57 93} Meta_nul {57 94} Meta_nul {57 95} Meta_nul {57 96} space {57 97} space {57 98} space {57 99} space {57 100} nul {57 101} nul {57 102} nul {57 103} nul {57 104} Meta_space {57 105} Meta_space {57 106} Meta_space {57 107} Meta_space {57 108} Meta_nul {57 109} Meta_nul {57 110} Meta_nul {57 111} Meta_nul {57 112} space {57 113} space {57 114} space {57 115} space {57 116} nul {57 117} nul {57 118} nul {57 119} nul {57 120} Meta_space {57 121} Meta_space {57 122} Meta_space {57 123} Meta_space {57 124} Meta_nul {57 125} Meta_nul {57 126} Meta_nul {57 127} Meta_nul {58 0} Caps_Lock {58 1} Caps_Lock {58 2} Caps_Lock {58 3} Caps_Lock {58 4} Caps_Lock {58 5} Caps_Lock {58 6} Caps_Lock {58 7} Caps_Lock {58 8} Caps_Lock {58 9} Caps_Lock {58 10} Caps_Lock {58 11} Caps_Lock {58 12} Caps_Lock {58 13} Caps_Lock {58 14} Caps_Lock {58 15} Caps_Lock {58 16} Caps_Lock {58 17} Caps_Lock {58 18} Caps_Lock {58 19} Caps_Lock {58 20} Caps_Lock {58 21} Caps_Lock {58 22} Caps_Lock {58 23} Caps_Lock {58 24} Caps_Lock {58 25} Caps_Lock {58 26} Caps_Lock {58 27} Caps_Lock {58 28} Caps_Lock {58 29} Caps_Lock {58 30} Caps_Lock {58 31} Caps_Lock {58 32} Caps_Lock {58 33} Caps_Lock {58 34} Caps_Lock {58 35} Caps_Lock {58 36} Caps_Lock {58 37} Caps_Lock {58 38} Caps_Lock {58 39} Caps_Lock {58 40} Caps_Lock {58 41} Caps_Lock {58 42} Caps_Lock {58 43} Caps_Lock {58 44} Caps_Lock {58 45} Caps_Lock {58 46} Caps_Lock {58 47} Caps_Lock {58 48} Caps_Lock {58 49} Caps_Lock {58 50} Caps_Lock {58 51} Caps_Lock {58 52} Caps_Lock {58 53} Caps_Lock {58 54} Caps_Lock {58 55} Caps_Lock {58 56} Caps_Lock {58 57} Caps_Lock {58 58} Caps_Lock {58 59} Caps_Lock {58 60} Caps_Lock {58 61} Caps_Lock {58 62} Caps_Lock {58 63} Caps_Lock {58 64} Caps_Lock {58 65} Caps_Lock {58 66} Caps_Lock {58 67} Caps_Lock {58 68} Caps_Lock {58 69} Caps_Lock {58 70} Caps_Lock {58 71} Caps_Lock {58 72} Caps_Lock {58 73} Caps_Lock {58 74} Caps_Lock {58 75} Caps_Lock {58 76} Caps_Lock {58 77} Caps_Lock {58 78} Caps_Lock {58 79} Caps_Lock {58 80} Caps_Lock {58 81} Caps_Lock {58 82} Caps_Lock {58 83} Caps_Lock {58 84} Caps_Lock {58 85} Caps_Lock {58 86} Caps_Lock {58 87} Caps_Lock {58 88} Caps_Lock {58 89} Caps_Lock {58 90} Caps_Lock {58 91} Caps_Lock {58 92} Caps_Lock {58 93} Caps_Lock {58 94} Caps_Lock {58 95} Caps_Lock {58 96} Caps_Lock {58 97} Caps_Lock {58 98} Caps_Lock {58 99} Caps_Lock {58 100} Caps_Lock {58 101} Caps_Lock {58 102} Caps_Lock {58 103} Caps_Lock {58 104} Caps_Lock {58 105} Caps_Lock {58 106} Caps_Lock {58 107} Caps_Lock {58 108} Caps_Lock {58 109} Caps_Lock {58 110} Caps_Lock {58 111} Caps_Lock {58 112} Caps_Lock {58 113} Caps_Lock {58 114} Caps_Lock {58 115} Caps_Lock {58 116} Caps_Lock {58 117} Caps_Lock {58 118} Caps_Lock {58 119} Caps_Lock {58 120} Caps_Lock {58 121} Caps_Lock {58 122} Caps_Lock {58 123} Caps_Lock {58 124} Caps_Lock {58 125} Caps_Lock {58 126} Caps_Lock {58 127} Caps_Lock {59 0} F1 {59 1} F13 {59 2} Console_13 {59 3} Console_25 {59 4} F25 {59 5} F37 {59 6} Console_13 {59 7} Console_25 {59 8} Console_1 {59 9} Console_13 {59 10} F1 {59 11} F1 {59 12} Console_1 {59 13} Console_13 {59 14} F1 {59 15} F1 {59 16} F1 {59 17} F13 {59 18} Console_13 {59 19} Console_25 {59 20} F25 {59 21} F37 {59 22} Console_13 {59 23} Console_25 {59 24} Console_1 {59 25} Console_13 {59 26} F1 {59 27} F1 {59 28} Console_1 {59 29} Console_13 {59 30} F1 {59 31} F1 {59 32} F1 {59 33} F13 {59 34} Console_13 {59 35} Console_25 {59 36} F25 {59 37} F37 {59 38} Console_13 {59 39} Console_25 {59 40} Console_1 {59 41} Console_13 {59 42} F1 {59 43} F1 {59 44} Console_1 {59 45} Console_13 {59 46} F1 {59 47} F1 {59 48} F1 {59 49} F13 {59 50} Console_13 {59 51} Console_25 {59 52} F25 {59 53} F37 {59 54} Console_13 {59 55} Console_25 {59 56} Console_1 {59 57} Console_13 {59 58} F1 {59 59} F1 {59 60} Console_1 {59 61} Console_13 {59 62} F1 {59 63} F1 {59 64} F1 {59 65} F13 {59 66} Console_13 {59 67} Console_25 {59 68} F25 {59 69} F37 {59 70} Console_13 {59 71} Console_25 {59 72} Console_1 {59 73} Console_13 {59 74} F1 {59 75} F1 {59 76} Console_1 {59 77} Console_13 {59 78} F1 {59 79} F1 {59 80} F1 {59 81} F13 {59 82} Console_13 {59 83} Console_25 {59 84} F25 {59 85} F37 {59 86} Console_13 {59 87} Console_25 {59 88} Console_1 {59 89} Console_13 {59 90} F1 {59 91} F1 {59 92} Console_1 {59 93} Console_13 {59 94} F1 {59 95} F1 {59 96} F1 {59 97} F13 {59 98} Console_13 {59 99} Console_25 {59 100} F25 {59 101} F37 {59 102} Console_13 {59 103} Console_25 {59 104} Console_1 {59 105} Console_13 {59 106} F1 {59 107} F1 {59 108} Console_1 {59 109} Console_13 {59 110} F1 {59 111} F1 {59 112} F1 {59 113} F13 {59 114} Console_13 {59 115} Console_25 {59 116} F25 {59 117} F37 {59 118} Console_13 {59 119} Console_25 {59 120} Console_1 {59 121} Console_13 {59 122} F1 {59 123} F1 {59 124} Console_1 {59 125} Console_13 {59 126} F1 {59 127} F1 {60 0} F2 {60 1} F14 {60 2} Console_14 {60 3} Console_26 {60 4} F26 {60 5} F38 {60 6} Console_14 {60 7} Console_26 {60 8} Console_2 {60 9} Console_14 {60 10} F2 {60 11} F2 {60 12} Console_2 {60 13} Console_14 {60 14} F2 {60 15} F2 {60 16} F2 {60 17} F14 {60 18} Console_14 {60 19} Console_26 {60 20} F26 {60 21} F38 {60 22} Console_14 {60 23} Console_26 {60 24} Console_2 {60 25} Console_14 {60 26} F2 {60 27} F2 {60 28} Console_2 {60 29} Console_14 {60 30} F2 {60 31} F2 {60 32} F2 {60 33} F14 {60 34} Console_14 {60 35} Console_26 {60 36} F26 {60 37} F38 {60 38} Console_14 {60 39} Console_26 {60 40} Console_2 {60 41} Console_14 {60 42} F2 {60 43} F2 {60 44} Console_2 {60 45} Console_14 {60 46} F2 {60 47} F2 {60 48} F2 {60 49} F14 {60 50} Console_14 {60 51} Console_26 {60 52} F26 {60 53} F38 {60 54} Console_14 {60 55} Console_26 {60 56} Console_2 {60 57} Console_14 {60 58} F2 {60 59} F2 {60 60} Console_2 {60 61} Console_14 {60 62} F2 {60 63} F2 {60 64} F2 {60 65} F14 {60 66} Console_14 {60 67} Console_26 {60 68} F26 {60 69} F38 {60 70} Console_14 {60 71} Console_26 {60 72} Console_2 {60 73} Console_14 {60 74} F2 {60 75} F2 {60 76} Console_2 {60 77} Console_14 {60 78} F2 {60 79} F2 {60 80} F2 {60 81} F14 {60 82} Console_14 {60 83} Console_26 {60 84} F26 {60 85} F38 {60 86} Console_14 {60 87} Console_26 {60 88} Console_2 {60 89} Console_14 {60 90} F2 {60 91} F2 {60 92} Console_2 {60 93} Console_14 {60 94} F2 {60 95} F2 {60 96} F2 {60 97} F14 {60 98} Console_14 {60 99} Console_26 {60 100} F26 {60 101} F38 {60 102} Console_14 {60 103} Console_26 {60 104} Console_2 {60 105} Console_14 {60 106} F2 {60 107} F2 {60 108} Console_2 {60 109} Console_14 {60 110} F2 {60 111} F2 {60 112} F2 {60 113} F14 {60 114} Console_14 {60 115} Console_26 {60 116} F26 {60 117} F38 {60 118} Console_14 {60 119} Console_26 {60 120} Console_2 {60 121} Console_14 {60 122} F2 {60 123} F2 {60 124} Console_2 {60 125} Console_14 {60 126} F2 {60 127} F2 {61 0} F3 {61 1} F15 {61 2} Console_15 {61 3} Console_27 {61 4} F27 {61 5} F39 {61 6} Console_15 {61 7} Console_27 {61 8} Console_3 {61 9} Console_15 {61 10} F3 {61 11} F3 {61 12} Console_3 {61 13} Console_15 {61 14} F3 {61 15} F3 {61 16} F3 {61 17} F15 {61 18} Console_15 {61 19} Console_27 {61 20} F27 {61 21} F39 {61 22} Console_15 {61 23} Console_27 {61 24} Console_3 {61 25} Console_15 {61 26} F3 {61 27} F3 {61 28} Console_3 {61 29} Console_15 {61 30} F3 {61 31} F3 {61 32} F3 {61 33} F15 {61 34} Console_15 {61 35} Console_27 {61 36} F27 {61 37} F39 {61 38} Console_15 {61 39} Console_27 {61 40} Console_3 {61 41} Console_15 {61 42} F3 {61 43} F3 {61 44} Console_3 {61 45} Console_15 {61 46} F3 {61 47} F3 {61 48} F3 {61 49} F15 {61 50} Console_15 {61 51} Console_27 {61 52} F27 {61 53} F39 {61 54} Console_15 {61 55} Console_27 {61 56} Console_3 {61 57} Console_15 {61 58} F3 {61 59} F3 {61 60} Console_3 {61 61} Console_15 {61 62} F3 {61 63} F3 {61 64} F3 {61 65} F15 {61 66} Console_15 {61 67} Console_27 {61 68} F27 {61 69} F39 {61 70} Console_15 {61 71} Console_27 {61 72} Console_3 {61 73} Console_15 {61 74} F3 {61 75} F3 {61 76} Console_3 {61 77} Console_15 {61 78} F3 {61 79} F3 {61 80} F3 {61 81} F15 {61 82} Console_15 {61 83} Console_27 {61 84} F27 {61 85} F39 {61 86} Console_15 {61 87} Console_27 {61 88} Console_3 {61 89} Console_15 {61 90} F3 {61 91} F3 {61 92} Console_3 {61 93} Console_15 {61 94} F3 {61 95} F3 {61 96} F3 {61 97} F15 {61 98} Console_15 {61 99} Console_27 {61 100} F27 {61 101} F39 {61 102} Console_15 {61 103} Console_27 {61 104} Console_3 {61 105} Console_15 {61 106} F3 {61 107} F3 {61 108} Console_3 {61 109} Console_15 {61 110} F3 {61 111} F3 {61 112} F3 {61 113} F15 {61 114} Console_15 {61 115} Console_27 {61 116} F27 {61 117} F39 {61 118} Console_15 {61 119} Console_27 {61 120} Console_3 {61 121} Console_15 {61 122} F3 {61 123} F3 {61 124} Console_3 {61 125} Console_15 {61 126} F3 {61 127} F3 {62 0} F4 {62 1} F16 {62 2} Console_16 {62 3} Console_28 {62 4} F28 {62 5} F40 {62 6} Console_16 {62 7} Console_28 {62 8} Console_4 {62 9} Console_16 {62 10} F4 {62 11} F4 {62 12} Console_4 {62 13} Console_16 {62 14} F4 {62 15} F4 {62 16} F4 {62 17} F16 {62 18} Console_16 {62 19} Console_28 {62 20} F28 {62 21} F40 {62 22} Console_16 {62 23} Console_28 {62 24} Console_4 {62 25} Console_16 {62 26} F4 {62 27} F4 {62 28} Console_4 {62 29} Console_16 {62 30} F4 {62 31} F4 {62 32} F4 {62 33} F16 {62 34} Console_16 {62 35} Console_28 {62 36} F28 {62 37} F40 {62 38} Console_16 {62 39} Console_28 {62 40} Console_4 {62 41} Console_16 {62 42} F4 {62 43} F4 {62 44} Console_4 {62 45} Console_16 {62 46} F4 {62 47} F4 {62 48} F4 {62 49} F16 {62 50} Console_16 {62 51} Console_28 {62 52} F28 {62 53} F40 {62 54} Console_16 {62 55} Console_28 {62 56} Console_4 {62 57} Console_16 {62 58} F4 {62 59} F4 {62 60} Console_4 {62 61} Console_16 {62 62} F4 {62 63} F4 {62 64} F4 {62 65} F16 {62 66} Console_16 {62 67} Console_28 {62 68} F28 {62 69} F40 {62 70} Console_16 {62 71} Console_28 {62 72} Console_4 {62 73} Console_16 {62 74} F4 {62 75} F4 {62 76} Console_4 {62 77} Console_16 {62 78} F4 {62 79} F4 {62 80} F4 {62 81} F16 {62 82} Console_16 {62 83} Console_28 {62 84} F28 {62 85} F40 {62 86} Console_16 {62 87} Console_28 {62 88} Console_4 {62 89} Console_16 {62 90} F4 {62 91} F4 {62 92} Console_4 {62 93} Console_16 {62 94} F4 {62 95} F4 {62 96} F4 {62 97} F16 {62 98} Console_16 {62 99} Console_28 {62 100} F28 {62 101} F40 {62 102} Console_16 {62 103} Console_28 {62 104} Console_4 {62 105} Console_16 {62 106} F4 {62 107} F4 {62 108} Console_4 {62 109} Console_16 {62 110} F4 {62 111} F4 {62 112} F4 {62 113} F16 {62 114} Console_16 {62 115} Console_28 {62 116} F28 {62 117} F40 {62 118} Console_16 {62 119} Console_28 {62 120} Console_4 {62 121} Console_16 {62 122} F4 {62 123} F4 {62 124} Console_4 {62 125} Console_16 {62 126} F4 {62 127} F4 {63 0} F5 {63 1} F17 {63 2} Console_17 {63 3} Console_29 {63 4} F29 {63 5} F41 {63 6} Console_17 {63 7} Console_29 {63 8} Console_5 {63 9} Console_17 {63 10} F5 {63 11} F5 {63 12} Console_5 {63 13} Console_17 {63 14} F5 {63 15} F5 {63 16} F5 {63 17} F17 {63 18} Console_17 {63 19} Console_29 {63 20} F29 {63 21} F41 {63 22} Console_17 {63 23} Console_29 {63 24} Console_5 {63 25} Console_17 {63 26} F5 {63 27} F5 {63 28} Console_5 {63 29} Console_17 {63 30} F5 {63 31} F5 {63 32} F5 {63 33} F17 {63 34} Console_17 {63 35} Console_29 {63 36} F29 {63 37} F41 {63 38} Console_17 {63 39} Console_29 {63 40} Console_5 {63 41} Console_17 {63 42} F5 {63 43} F5 {63 44} Console_5 {63 45} Console_17 {63 46} F5 {63 47} F5 {63 48} F5 {63 49} F17 {63 50} Console_17 {63 51} Console_29 {63 52} F29 {63 53} F41 {63 54} Console_17 {63 55} Console_29 {63 56} Console_5 {63 57} Console_17 {63 58} F5 {63 59} F5 {63 60} Console_5 {63 61} Console_17 {63 62} F5 {63 63} F5 {63 64} F5 {63 65} F17 {63 66} Console_17 {63 67} Console_29 {63 68} F29 {63 69} F41 {63 70} Console_17 {63 71} Console_29 {63 72} Console_5 {63 73} Console_17 {63 74} F5 {63 75} F5 {63 76} Console_5 {63 77} Console_17 {63 78} F5 {63 79} F5 {63 80} F5 {63 81} F17 {63 82} Console_17 {63 83} Console_29 {63 84} F29 {63 85} F41 {63 86} Console_17 {63 87} Console_29 {63 88} Console_5 {63 89} Console_17 {63 90} F5 {63 91} F5 {63 92} Console_5 {63 93} Console_17 {63 94} F5 {63 95} F5 {63 96} F5 {63 97} F17 {63 98} Console_17 {63 99} Console_29 {63 100} F29 {63 101} F41 {63 102} Console_17 {63 103} Console_29 {63 104} Console_5 {63 105} Console_17 {63 106} F5 {63 107} F5 {63 108} Console_5 {63 109} Console_17 {63 110} F5 {63 111} F5 {63 112} F5 {63 113} F17 {63 114} Console_17 {63 115} Console_29 {63 116} F29 {63 117} F41 {63 118} Console_17 {63 119} Console_29 {63 120} Console_5 {63 121} Console_17 {63 122} F5 {63 123} F5 {63 124} Console_5 {63 125} Console_17 {63 126} F5 {63 127} F5 {64 0} F6 {64 1} F18 {64 2} Console_18 {64 3} Console_30 {64 4} F30 {64 5} F42 {64 6} Console_18 {64 7} Console_30 {64 8} Console_6 {64 9} Console_18 {64 10} F6 {64 11} F6 {64 12} Console_6 {64 13} Console_18 {64 14} F6 {64 15} F6 {64 16} F6 {64 17} F18 {64 18} Console_18 {64 19} Console_30 {64 20} F30 {64 21} F42 {64 22} Console_18 {64 23} Console_30 {64 24} Console_6 {64 25} Console_18 {64 26} F6 {64 27} F6 {64 28} Console_6 {64 29} Console_18 {64 30} F6 {64 31} F6 {64 32} F6 {64 33} F18 {64 34} Console_18 {64 35} Console_30 {64 36} F30 {64 37} F42 {64 38} Console_18 {64 39} Console_30 {64 40} Console_6 {64 41} Console_18 {64 42} F6 {64 43} F6 {64 44} Console_6 {64 45} Console_18 {64 46} F6 {64 47} F6 {64 48} F6 {64 49} F18 {64 50} Console_18 {64 51} Console_30 {64 52} F30 {64 53} F42 {64 54} Console_18 {64 55} Console_30 {64 56} Console_6 {64 57} Console_18 {64 58} F6 {64 59} F6 {64 60} Console_6 {64 61} Console_18 {64 62} F6 {64 63} F6 {64 64} F6 {64 65} F18 {64 66} Console_18 {64 67} Console_30 {64 68} F30 {64 69} F42 {64 70} Console_18 {64 71} Console_30 {64 72} Console_6 {64 73} Console_18 {64 74} F6 {64 75} F6 {64 76} Console_6 {64 77} Console_18 {64 78} F6 {64 79} F6 {64 80} F6 {64 81} F18 {64 82} Console_18 {64 83} Console_30 {64 84} F30 {64 85} F42 {64 86} Console_18 {64 87} Console_30 {64 88} Console_6 {64 89} Console_18 {64 90} F6 {64 91} F6 {64 92} Console_6 {64 93} Console_18 {64 94} F6 {64 95} F6 {64 96} F6 {64 97} F18 {64 98} Console_18 {64 99} Console_30 {64 100} F30 {64 101} F42 {64 102} Console_18 {64 103} Console_30 {64 104} Console_6 {64 105} Console_18 {64 106} F6 {64 107} F6 {64 108} Console_6 {64 109} Console_18 {64 110} F6 {64 111} F6 {64 112} F6 {64 113} F18 {64 114} Console_18 {64 115} Console_30 {64 116} F30 {64 117} F42 {64 118} Console_18 {64 119} Console_30 {64 120} Console_6 {64 121} Console_18 {64 122} F6 {64 123} F6 {64 124} Console_6 {64 125} Console_18 {64 126} F6 {64 127} F6 {65 0} F7 {65 1} F19 {65 2} Console_19 {65 3} Console_31 {65 4} F31 {65 5} F43 {65 6} Console_19 {65 7} Console_31 {65 8} Console_7 {65 9} Console_19 {65 10} F7 {65 11} F7 {65 12} Console_7 {65 13} Console_19 {65 14} F7 {65 15} F7 {65 16} F7 {65 17} F19 {65 18} Console_19 {65 19} Console_31 {65 20} F31 {65 21} F43 {65 22} Console_19 {65 23} Console_31 {65 24} Console_7 {65 25} Console_19 {65 26} F7 {65 27} F7 {65 28} Console_7 {65 29} Console_19 {65 30} F7 {65 31} F7 {65 32} F7 {65 33} F19 {65 34} Console_19 {65 35} Console_31 {65 36} F31 {65 37} F43 {65 38} Console_19 {65 39} Console_31 {65 40} Console_7 {65 41} Console_19 {65 42} F7 {65 43} F7 {65 44} Console_7 {65 45} Console_19 {65 46} F7 {65 47} F7 {65 48} F7 {65 49} F19 {65 50} Console_19 {65 51} Console_31 {65 52} F31 {65 53} F43 {65 54} Console_19 {65 55} Console_31 {65 56} Console_7 {65 57} Console_19 {65 58} F7 {65 59} F7 {65 60} Console_7 {65 61} Console_19 {65 62} F7 {65 63} F7 {65 64} F7 {65 65} F19 {65 66} Console_19 {65 67} Console_31 {65 68} F31 {65 69} F43 {65 70} Console_19 {65 71} Console_31 {65 72} Console_7 {65 73} Console_19 {65 74} F7 {65 75} F7 {65 76} Console_7 {65 77} Console_19 {65 78} F7 {65 79} F7 {65 80} F7 {65 81} F19 {65 82} Console_19 {65 83} Console_31 {65 84} F31 {65 85} F43 {65 86} Console_19 {65 87} Console_31 {65 88} Console_7 {65 89} Console_19 {65 90} F7 {65 91} F7 {65 92} Console_7 {65 93} Console_19 {65 94} F7 {65 95} F7 {65 96} F7 {65 97} F19 {65 98} Console_19 {65 99} Console_31 {65 100} F31 {65 101} F43 {65 102} Console_19 {65 103} Console_31 {65 104} Console_7 {65 105} Console_19 {65 106} F7 {65 107} F7 {65 108} Console_7 {65 109} Console_19 {65 110} F7 {65 111} F7 {65 112} F7 {65 113} F19 {65 114} Console_19 {65 115} Console_31 {65 116} F31 {65 117} F43 {65 118} Console_19 {65 119} Console_31 {65 120} Console_7 {65 121} Console_19 {65 122} F7 {65 123} F7 {65 124} Console_7 {65 125} Console_19 {65 126} F7 {65 127} F7 {66 0} F8 {66 1} F20 {66 2} Console_20 {66 3} Console_32 {66 4} F32 {66 5} F44 {66 6} Console_20 {66 7} Console_32 {66 8} Console_8 {66 9} Console_20 {66 10} F8 {66 11} F8 {66 12} Console_8 {66 13} Console_20 {66 14} F8 {66 15} F8 {66 16} F8 {66 17} F20 {66 18} Console_20 {66 19} Console_32 {66 20} F32 {66 21} F44 {66 22} Console_20 {66 23} Console_32 {66 24} Console_8 {66 25} Console_20 {66 26} F8 {66 27} F8 {66 28} Console_8 {66 29} Console_20 {66 30} F8 {66 31} F8 {66 32} F8 {66 33} F20 {66 34} Console_20 {66 35} Console_32 {66 36} F32 {66 37} F44 {66 38} Console_20 {66 39} Console_32 {66 40} Console_8 {66 41} Console_20 {66 42} F8 {66 43} F8 {66 44} Console_8 {66 45} Console_20 {66 46} F8 {66 47} F8 {66 48} F8 {66 49} F20 {66 50} Console_20 {66 51} Console_32 {66 52} F32 {66 53} F44 {66 54} Console_20 {66 55} Console_32 {66 56} Console_8 {66 57} Console_20 {66 58} F8 {66 59} F8 {66 60} Console_8 {66 61} Console_20 {66 62} F8 {66 63} F8 {66 64} F8 {66 65} F20 {66 66} Console_20 {66 67} Console_32 {66 68} F32 {66 69} F44 {66 70} Console_20 {66 71} Console_32 {66 72} Console_8 {66 73} Console_20 {66 74} F8 {66 75} F8 {66 76} Console_8 {66 77} Console_20 {66 78} F8 {66 79} F8 {66 80} F8 {66 81} F20 {66 82} Console_20 {66 83} Console_32 {66 84} F32 {66 85} F44 {66 86} Console_20 {66 87} Console_32 {66 88} Console_8 {66 89} Console_20 {66 90} F8 {66 91} F8 {66 92} Console_8 {66 93} Console_20 {66 94} F8 {66 95} F8 {66 96} F8 {66 97} F20 {66 98} Console_20 {66 99} Console_32 {66 100} F32 {66 101} F44 {66 102} Console_20 {66 103} Console_32 {66 104} Console_8 {66 105} Console_20 {66 106} F8 {66 107} F8 {66 108} Console_8 {66 109} Console_20 {66 110} F8 {66 111} F8 {66 112} F8 {66 113} F20 {66 114} Console_20 {66 115} Console_32 {66 116} F32 {66 117} F44 {66 118} Console_20 {66 119} Console_32 {66 120} Console_8 {66 121} Console_20 {66 122} F8 {66 123} F8 {66 124} Console_8 {66 125} Console_20 {66 126} F8 {66 127} F8 {67 0} F9 {67 1} F21 {67 2} Console_21 {67 3} Console_33 {67 4} F33 {67 5} F45 {67 6} Console_21 {67 7} Console_33 {67 8} Console_9 {67 9} Console_21 {67 10} F9 {67 11} F9 {67 12} Console_9 {67 13} Console_21 {67 14} F9 {67 15} F9 {67 16} F9 {67 17} F21 {67 18} Console_21 {67 19} Console_33 {67 20} F33 {67 21} F45 {67 22} Console_21 {67 23} Console_33 {67 24} Console_9 {67 25} Console_21 {67 26} F9 {67 27} F9 {67 28} Console_9 {67 29} Console_21 {67 30} F9 {67 31} F9 {67 32} F9 {67 33} F21 {67 34} Console_21 {67 35} Console_33 {67 36} F33 {67 37} F45 {67 38} Console_21 {67 39} Console_33 {67 40} Console_9 {67 41} Console_21 {67 42} F9 {67 43} F9 {67 44} Console_9 {67 45} Console_21 {67 46} F9 {67 47} F9 {67 48} F9 {67 49} F21 {67 50} Console_21 {67 51} Console_33 {67 52} F33 {67 53} F45 {67 54} Console_21 {67 55} Console_33 {67 56} Console_9 {67 57} Console_21 {67 58} F9 {67 59} F9 {67 60} Console_9 {67 61} Console_21 {67 62} F9 {67 63} F9 {67 64} F9 {67 65} F21 {67 66} Console_21 {67 67} Console_33 {67 68} F33 {67 69} F45 {67 70} Console_21 {67 71} Console_33 {67 72} Console_9 {67 73} Console_21 {67 74} F9 {67 75} F9 {67 76} Console_9 {67 77} Console_21 {67 78} F9 {67 79} F9 {67 80} F9 {67 81} F21 {67 82} Console_21 {67 83} Console_33 {67 84} F33 {67 85} F45 {67 86} Console_21 {67 87} Console_33 {67 88} Console_9 {67 89} Console_21 {67 90} F9 {67 91} F9 {67 92} Console_9 {67 93} Console_21 {67 94} F9 {67 95} F9 {67 96} F9 {67 97} F21 {67 98} Console_21 {67 99} Console_33 {67 100} F33 {67 101} F45 {67 102} Console_21 {67 103} Console_33 {67 104} Console_9 {67 105} Console_21 {67 106} F9 {67 107} F9 {67 108} Console_9 {67 109} Console_21 {67 110} F9 {67 111} F9 {67 112} F9 {67 113} F21 {67 114} Console_21 {67 115} Console_33 {67 116} F33 {67 117} F45 {67 118} Console_21 {67 119} Console_33 {67 120} Console_9 {67 121} Console_21 {67 122} F9 {67 123} F9 {67 124} Console_9 {67 125} Console_21 {67 126} F9 {67 127} F9 {68 0} F10 {68 1} F22 {68 2} Console_22 {68 3} Console_34 {68 4} F34 {68 5} F46 {68 6} Console_22 {68 7} Console_34 {68 8} Console_10 {68 9} Console_22 {68 10} F10 {68 11} F10 {68 12} Console_10 {68 13} Console_22 {68 14} F10 {68 15} F10 {68 16} F10 {68 17} F22 {68 18} Console_22 {68 19} Console_34 {68 20} F34 {68 21} F46 {68 22} Console_22 {68 23} Console_34 {68 24} Console_10 {68 25} Console_22 {68 26} F10 {68 27} F10 {68 28} Console_10 {68 29} Console_22 {68 30} F10 {68 31} F10 {68 32} F10 {68 33} F22 {68 34} Console_22 {68 35} Console_34 {68 36} F34 {68 37} F46 {68 38} Console_22 {68 39} Console_34 {68 40} Console_10 {68 41} Console_22 {68 42} F10 {68 43} F10 {68 44} Console_10 {68 45} Console_22 {68 46} F10 {68 47} F10 {68 48} F10 {68 49} F22 {68 50} Console_22 {68 51} Console_34 {68 52} F34 {68 53} F46 {68 54} Console_22 {68 55} Console_34 {68 56} Console_10 {68 57} Console_22 {68 58} F10 {68 59} F10 {68 60} Console_10 {68 61} Console_22 {68 62} F10 {68 63} F10 {68 64} F10 {68 65} F22 {68 66} Console_22 {68 67} Console_34 {68 68} F34 {68 69} F46 {68 70} Console_22 {68 71} Console_34 {68 72} Console_10 {68 73} Console_22 {68 74} F10 {68 75} F10 {68 76} Console_10 {68 77} Console_22 {68 78} F10 {68 79} F10 {68 80} F10 {68 81} F22 {68 82} Console_22 {68 83} Console_34 {68 84} F34 {68 85} F46 {68 86} Console_22 {68 87} Console_34 {68 88} Console_10 {68 89} Console_22 {68 90} F10 {68 91} F10 {68 92} Console_10 {68 93} Console_22 {68 94} F10 {68 95} F10 {68 96} F10 {68 97} F22 {68 98} Console_22 {68 99} Console_34 {68 100} F34 {68 101} F46 {68 102} Console_22 {68 103} Console_34 {68 104} Console_10 {68 105} Console_22 {68 106} F10 {68 107} F10 {68 108} Console_10 {68 109} Console_22 {68 110} F10 {68 111} F10 {68 112} F10 {68 113} F22 {68 114} Console_22 {68 115} Console_34 {68 116} F34 {68 117} F46 {68 118} Console_22 {68 119} Console_34 {68 120} Console_10 {68 121} Console_22 {68 122} F10 {68 123} F10 {68 124} Console_10 {68 125} Console_22 {68 126} F10 {68 127} F10 {69 0} Num_Lock {69 1} Num_Lock {69 2} Hex_A {69 3} Num_Lock {69 4} Num_Lock {69 5} Num_Lock {69 6} Num_Lock {69 7} Num_Lock {69 8} Num_Lock {69 9} Hex_A {69 10} Num_Lock {69 11} Num_Lock {69 12} Num_Lock {69 13} Num_Lock {69 14} Num_Lock {69 15} Num_Lock {69 16} Num_Lock {69 17} Num_Lock {69 18} Hex_A {69 19} Num_Lock {69 20} Num_Lock {69 21} Num_Lock {69 22} Num_Lock {69 23} Num_Lock {69 24} Num_Lock {69 25} Hex_A {69 26} Num_Lock {69 27} Num_Lock {69 28} Num_Lock {69 29} Num_Lock {69 30} Num_Lock {69 31} Num_Lock {69 32} Num_Lock {69 33} Num_Lock {69 34} Hex_A {69 35} Num_Lock {69 36} Num_Lock {69 37} Num_Lock {69 38} Num_Lock {69 39} Num_Lock {69 40} Num_Lock {69 41} Hex_A {69 42} Num_Lock {69 43} Num_Lock {69 44} Num_Lock {69 45} Num_Lock {69 46} Num_Lock {69 47} Num_Lock {69 48} Num_Lock {69 49} Num_Lock {69 50} Hex_A {69 51} Num_Lock {69 52} Num_Lock {69 53} Num_Lock {69 54} Num_Lock {69 55} Num_Lock {69 56} Num_Lock {69 57} Hex_A {69 58} Num_Lock {69 59} Num_Lock {69 60} Num_Lock {69 61} Num_Lock {69 62} Num_Lock {69 63} Num_Lock {69 64} Num_Lock {69 65} Num_Lock {69 66} Hex_A {69 67} Num_Lock {69 68} Num_Lock {69 69} Num_Lock {69 70} Num_Lock {69 71} Num_Lock {69 72} Num_Lock {69 73} Hex_A {69 74} Num_Lock {69 75} Num_Lock {69 76} Num_Lock {69 77} Num_Lock {69 78} Num_Lock {69 79} Num_Lock {69 80} Num_Lock {69 81} Num_Lock {69 82} Hex_A {69 83} Num_Lock {69 84} Num_Lock {69 85} Num_Lock {69 86} Num_Lock {69 87} Num_Lock {69 88} Num_Lock {69 89} Hex_A {69 90} Num_Lock {69 91} Num_Lock {69 92} Num_Lock {69 93} Num_Lock {69 94} Num_Lock {69 95} Num_Lock {69 96} Num_Lock {69 97} Num_Lock {69 98} Hex_A {69 99} Num_Lock {69 100} Num_Lock {69 101} Num_Lock {69 102} Num_Lock {69 103} Num_Lock {69 104} Num_Lock {69 105} Hex_A {69 106} Num_Lock {69 107} Num_Lock {69 108} Num_Lock {69 109} Num_Lock {69 110} Num_Lock {69 111} Num_Lock {69 112} Num_Lock {69 113} Num_Lock {69 114} Hex_A {69 115} Num_Lock {69 116} Num_Lock {69 117} Num_Lock {69 118} Num_Lock {69 119} Num_Lock {69 120} Num_Lock {69 121} Hex_A {69 122} Num_Lock {69 123} Num_Lock {69 124} Num_Lock {69 125} Num_Lock {69 126} Num_Lock {69 127} Num_Lock {70 0} Scroll_Lock {70 1} Show_Memory {70 2} Show_Registers {70 3} Scroll_Lock {70 4} Show_State {70 5} Scroll_Lock {70 6} Scroll_Lock {70 7} Scroll_Lock {70 8} Show_Registers {70 9} Scroll_Lock {70 10} Scroll_Lock {70 11} Scroll_Lock {70 12} Scroll_Lock {70 13} Scroll_Lock {70 14} Scroll_Lock {70 15} Scroll_Lock {70 16} Scroll_Lock {70 17} Show_Memory {70 18} Show_Registers {70 19} Scroll_Lock {70 20} Show_State {70 21} Scroll_Lock {70 22} Scroll_Lock {70 23} Scroll_Lock {70 24} Show_Registers {70 25} Scroll_Lock {70 26} Scroll_Lock {70 27} Scroll_Lock {70 28} Scroll_Lock {70 29} Scroll_Lock {70 30} Scroll_Lock {70 31} Scroll_Lock {70 32} Scroll_Lock {70 33} Show_Memory {70 34} Show_Registers {70 35} Scroll_Lock {70 36} Show_State {70 37} Scroll_Lock {70 38} Scroll_Lock {70 39} Scroll_Lock {70 40} Show_Registers {70 41} Scroll_Lock {70 42} Scroll_Lock {70 43} Scroll_Lock {70 44} Scroll_Lock {70 45} Scroll_Lock {70 46} Scroll_Lock {70 47} Scroll_Lock {70 48} Scroll_Lock {70 49} Show_Memory {70 50} Show_Registers {70 51} Scroll_Lock {70 52} Show_State {70 53} Scroll_Lock {70 54} Scroll_Lock {70 55} Scroll_Lock {70 56} Show_Registers {70 57} Scroll_Lock {70 58} Scroll_Lock {70 59} Scroll_Lock {70 60} Scroll_Lock {70 61} Scroll_Lock {70 62} Scroll_Lock {70 63} Scroll_Lock {70 64} Scroll_Lock {70 65} Show_Memory {70 66} Show_Registers {70 67} Scroll_Lock {70 68} Show_State {70 69} Scroll_Lock {70 70} Scroll_Lock {70 71} Scroll_Lock {70 72} Show_Registers {70 73} Scroll_Lock {70 74} Scroll_Lock {70 75} Scroll_Lock {70 76} Scroll_Lock {70 77} Scroll_Lock {70 78} Scroll_Lock {70 79} Scroll_Lock {70 80} Scroll_Lock {70 81} Show_Memory {70 82} Show_Registers {70 83} Scroll_Lock {70 84} Show_State {70 85} Scroll_Lock {70 86} Scroll_Lock {70 87} Scroll_Lock {70 88} Show_Registers {70 89} Scroll_Lock {70 90} Scroll_Lock {70 91} Scroll_Lock {70 92} Scroll_Lock {70 93} Scroll_Lock {70 94} Scroll_Lock {70 95} Scroll_Lock {70 96} Scroll_Lock {70 97} Show_Memory {70 98} Show_Registers {70 99} Scroll_Lock {70 100} Show_State {70 101} Scroll_Lock {70 102} Scroll_Lock {70 103} Scroll_Lock {70 104} Show_Registers {70 105} Scroll_Lock {70 106} Scroll_Lock {70 107} Scroll_Lock {70 108} Scroll_Lock {70 109} Scroll_Lock {70 110} Scroll_Lock {70 111} Scroll_Lock {70 112} Scroll_Lock {70 113} Show_Memory {70 114} Show_Registers {70 115} Scroll_Lock {70 116} Show_State {70 117} Scroll_Lock {70 118} Scroll_Lock {70 119} Scroll_Lock {70 120} Show_Registers {70 121} Scroll_Lock {70 122} Scroll_Lock {70 123} Scroll_Lock {70 124} Scroll_Lock {70 125} Scroll_Lock {70 126} Scroll_Lock {70 127} Scroll_Lock {71 0} KP_7 {71 1} KP_7 {71 2} Hex_7 {71 3} KP_7 {71 4} KP_7 {71 5} KP_7 {71 6} KP_7 {71 7} KP_7 {71 8} Ascii_7 {71 9} Hex_7 {71 10} KP_7 {71 11} KP_7 {71 12} KP_7 {71 13} KP_7 {71 14} KP_7 {71 15} KP_7 {71 16} KP_7 {71 17} KP_7 {71 18} Hex_7 {71 19} KP_7 {71 20} KP_7 {71 21} KP_7 {71 22} KP_7 {71 23} KP_7 {71 24} Ascii_7 {71 25} Hex_7 {71 26} KP_7 {71 27} KP_7 {71 28} KP_7 {71 29} KP_7 {71 30} KP_7 {71 31} KP_7 {71 32} KP_7 {71 33} KP_7 {71 34} Hex_7 {71 35} KP_7 {71 36} KP_7 {71 37} KP_7 {71 38} KP_7 {71 39} KP_7 {71 40} Ascii_7 {71 41} Hex_7 {71 42} KP_7 {71 43} KP_7 {71 44} KP_7 {71 45} KP_7 {71 46} KP_7 {71 47} KP_7 {71 48} KP_7 {71 49} KP_7 {71 50} Hex_7 {71 51} KP_7 {71 52} KP_7 {71 53} KP_7 {71 54} KP_7 {71 55} KP_7 {71 56} Ascii_7 {71 57} Hex_7 {71 58} KP_7 {71 59} KP_7 {71 60} KP_7 {71 61} KP_7 {71 62} KP_7 {71 63} KP_7 {71 64} KP_7 {71 65} KP_7 {71 66} Hex_7 {71 67} KP_7 {71 68} KP_7 {71 69} KP_7 {71 70} KP_7 {71 71} KP_7 {71 72} Ascii_7 {71 73} Hex_7 {71 74} KP_7 {71 75} KP_7 {71 76} KP_7 {71 77} KP_7 {71 78} KP_7 {71 79} KP_7 {71 80} KP_7 {71 81} KP_7 {71 82} Hex_7 {71 83} KP_7 {71 84} KP_7 {71 85} KP_7 {71 86} KP_7 {71 87} KP_7 {71 88} Ascii_7 {71 89} Hex_7 {71 90} KP_7 {71 91} KP_7 {71 92} KP_7 {71 93} KP_7 {71 94} KP_7 {71 95} KP_7 {71 96} KP_7 {71 97} KP_7 {71 98} Hex_7 {71 99} KP_7 {71 100} KP_7 {71 101} KP_7 {71 102} KP_7 {71 103} KP_7 {71 104} Ascii_7 {71 105} Hex_7 {71 106} KP_7 {71 107} KP_7 {71 108} KP_7 {71 109} KP_7 {71 110} KP_7 {71 111} KP_7 {71 112} KP_7 {71 113} KP_7 {71 114} Hex_7 {71 115} KP_7 {71 116} KP_7 {71 117} KP_7 {71 118} KP_7 {71 119} KP_7 {71 120} Ascii_7 {71 121} Hex_7 {71 122} KP_7 {71 123} KP_7 {71 124} KP_7 {71 125} KP_7 {71 126} KP_7 {71 127} KP_7 {72 0} KP_8 {72 1} KP_8 {72 2} Hex_8 {72 3} KP_8 {72 4} KP_8 {72 5} KP_8 {72 6} KP_8 {72 7} KP_8 {72 8} Ascii_8 {72 9} Hex_8 {72 10} KP_8 {72 11} KP_8 {72 12} KP_8 {72 13} KP_8 {72 14} KP_8 {72 15} KP_8 {72 16} KP_8 {72 17} KP_8 {72 18} Hex_8 {72 19} KP_8 {72 20} KP_8 {72 21} KP_8 {72 22} KP_8 {72 23} KP_8 {72 24} Ascii_8 {72 25} Hex_8 {72 26} KP_8 {72 27} KP_8 {72 28} KP_8 {72 29} KP_8 {72 30} KP_8 {72 31} KP_8 {72 32} KP_8 {72 33} KP_8 {72 34} Hex_8 {72 35} KP_8 {72 36} KP_8 {72 37} KP_8 {72 38} KP_8 {72 39} KP_8 {72 40} Ascii_8 {72 41} Hex_8 {72 42} KP_8 {72 43} KP_8 {72 44} KP_8 {72 45} KP_8 {72 46} KP_8 {72 47} KP_8 {72 48} KP_8 {72 49} KP_8 {72 50} Hex_8 {72 51} KP_8 {72 52} KP_8 {72 53} KP_8 {72 54} KP_8 {72 55} KP_8 {72 56} Ascii_8 {72 57} Hex_8 {72 58} KP_8 {72 59} KP_8 {72 60} KP_8 {72 61} KP_8 {72 62} KP_8 {72 63} KP_8 {72 64} KP_8 {72 65} KP_8 {72 66} Hex_8 {72 67} KP_8 {72 68} KP_8 {72 69} KP_8 {72 70} KP_8 {72 71} KP_8 {72 72} Ascii_8 {72 73} Hex_8 {72 74} KP_8 {72 75} KP_8 {72 76} KP_8 {72 77} KP_8 {72 78} KP_8 {72 79} KP_8 {72 80} KP_8 {72 81} KP_8 {72 82} Hex_8 {72 83} KP_8 {72 84} KP_8 {72 85} KP_8 {72 86} KP_8 {72 87} KP_8 {72 88} Ascii_8 {72 89} Hex_8 {72 90} KP_8 {72 91} KP_8 {72 92} KP_8 {72 93} KP_8 {72 94} KP_8 {72 95} KP_8 {72 96} KP_8 {72 97} KP_8 {72 98} Hex_8 {72 99} KP_8 {72 100} KP_8 {72 101} KP_8 {72 102} KP_8 {72 103} KP_8 {72 104} Ascii_8 {72 105} Hex_8 {72 106} KP_8 {72 107} KP_8 {72 108} KP_8 {72 109} KP_8 {72 110} KP_8 {72 111} KP_8 {72 112} KP_8 {72 113} KP_8 {72 114} Hex_8 {72 115} KP_8 {72 116} KP_8 {72 117} KP_8 {72 118} KP_8 {72 119} KP_8 {72 120} Ascii_8 {72 121} Hex_8 {72 122} KP_8 {72 123} KP_8 {72 124} KP_8 {72 125} KP_8 {72 126} KP_8 {72 127} KP_8 {73 0} KP_9 {73 1} KP_9 {73 2} Hex_9 {73 3} KP_9 {73 4} KP_9 {73 5} KP_9 {73 6} KP_9 {73 7} KP_9 {73 8} Ascii_9 {73 9} Hex_9 {73 10} KP_9 {73 11} KP_9 {73 12} KP_9 {73 13} KP_9 {73 14} KP_9 {73 15} KP_9 {73 16} KP_9 {73 17} KP_9 {73 18} Hex_9 {73 19} KP_9 {73 20} KP_9 {73 21} KP_9 {73 22} KP_9 {73 23} KP_9 {73 24} Ascii_9 {73 25} Hex_9 {73 26} KP_9 {73 27} KP_9 {73 28} KP_9 {73 29} KP_9 {73 30} KP_9 {73 31} KP_9 {73 32} KP_9 {73 33} KP_9 {73 34} Hex_9 {73 35} KP_9 {73 36} KP_9 {73 37} KP_9 {73 38} KP_9 {73 39} KP_9 {73 40} Ascii_9 {73 41} Hex_9 {73 42} KP_9 {73 43} KP_9 {73 44} KP_9 {73 45} KP_9 {73 46} KP_9 {73 47} KP_9 {73 48} KP_9 {73 49} KP_9 {73 50} Hex_9 {73 51} KP_9 {73 52} KP_9 {73 53} KP_9 {73 54} KP_9 {73 55} KP_9 {73 56} Ascii_9 {73 57} Hex_9 {73 58} KP_9 {73 59} KP_9 {73 60} KP_9 {73 61} KP_9 {73 62} KP_9 {73 63} KP_9 {73 64} KP_9 {73 65} KP_9 {73 66} Hex_9 {73 67} KP_9 {73 68} KP_9 {73 69} KP_9 {73 70} KP_9 {73 71} KP_9 {73 72} Ascii_9 {73 73} Hex_9 {73 74} KP_9 {73 75} KP_9 {73 76} KP_9 {73 77} KP_9 {73 78} KP_9 {73 79} KP_9 {73 80} KP_9 {73 81} KP_9 {73 82} Hex_9 {73 83} KP_9 {73 84} KP_9 {73 85} KP_9 {73 86} KP_9 {73 87} KP_9 {73 88} Ascii_9 {73 89} Hex_9 {73 90} KP_9 {73 91} KP_9 {73 92} KP_9 {73 93} KP_9 {73 94} KP_9 {73 95} KP_9 {73 96} KP_9 {73 97} KP_9 {73 98} Hex_9 {73 99} KP_9 {73 100} KP_9 {73 101} KP_9 {73 102} KP_9 {73 103} KP_9 {73 104} Ascii_9 {73 105} Hex_9 {73 106} KP_9 {73 107} KP_9 {73 108} KP_9 {73 109} KP_9 {73 110} KP_9 {73 111} KP_9 {73 112} KP_9 {73 113} KP_9 {73 114} Hex_9 {73 115} KP_9 {73 116} KP_9 {73 117} KP_9 {73 118} KP_9 {73 119} KP_9 {73 120} Ascii_9 {73 121} Hex_9 {73 122} KP_9 {73 123} KP_9 {73 124} KP_9 {73 125} KP_9 {73 126} KP_9 {73 127} KP_9 {74 0} KP_Subtract {74 1} KP_Subtract {74 2} Hex_D {74 3} KP_Subtract {74 4} KP_Subtract {74 5} KP_Subtract {74 6} KP_Subtract {74 7} KP_Subtract {74 8} KP_Subtract {74 9} Hex_D {74 10} KP_Subtract {74 11} KP_Subtract {74 12} KP_Subtract {74 13} KP_Subtract {74 14} KP_Subtract {74 15} KP_Subtract {74 16} KP_Subtract {74 17} KP_Subtract {74 18} Hex_D {74 19} KP_Subtract {74 20} KP_Subtract {74 21} KP_Subtract {74 22} KP_Subtract {74 23} KP_Subtract {74 24} KP_Subtract {74 25} Hex_D {74 26} KP_Subtract {74 27} KP_Subtract {74 28} KP_Subtract {74 29} KP_Subtract {74 30} KP_Subtract {74 31} KP_Subtract {74 32} KP_Subtract {74 33} KP_Subtract {74 34} Hex_D {74 35} KP_Subtract {74 36} KP_Subtract {74 37} KP_Subtract {74 38} KP_Subtract {74 39} KP_Subtract {74 40} KP_Subtract {74 41} Hex_D {74 42} KP_Subtract {74 43} KP_Subtract {74 44} KP_Subtract {74 45} KP_Subtract {74 46} KP_Subtract {74 47} KP_Subtract {74 48} KP_Subtract {74 49} KP_Subtract {74 50} Hex_D {74 51} KP_Subtract {74 52} KP_Subtract {74 53} KP_Subtract {74 54} KP_Subtract {74 55} KP_Subtract {74 56} KP_Subtract {74 57} Hex_D {74 58} KP_Subtract {74 59} KP_Subtract {74 60} KP_Subtract {74 61} KP_Subtract {74 62} KP_Subtract {74 63} KP_Subtract {74 64} KP_Subtract {74 65} KP_Subtract {74 66} Hex_D {74 67} KP_Subtract {74 68} KP_Subtract {74 69} KP_Subtract {74 70} KP_Subtract {74 71} KP_Subtract {74 72} KP_Subtract {74 73} Hex_D {74 74} KP_Subtract {74 75} KP_Subtract {74 76} KP_Subtract {74 77} KP_Subtract {74 78} KP_Subtract {74 79} KP_Subtract {74 80} KP_Subtract {74 81} KP_Subtract {74 82} Hex_D {74 83} KP_Subtract {74 84} KP_Subtract {74 85} KP_Subtract {74 86} KP_Subtract {74 87} KP_Subtract {74 88} KP_Subtract {74 89} Hex_D {74 90} KP_Subtract {74 91} KP_Subtract {74 92} KP_Subtract {74 93} KP_Subtract {74 94} KP_Subtract {74 95} KP_Subtract {74 96} KP_Subtract {74 97} KP_Subtract {74 98} Hex_D {74 99} KP_Subtract {74 100} KP_Subtract {74 101} KP_Subtract {74 102} KP_Subtract {74 103} KP_Subtract {74 104} KP_Subtract {74 105} Hex_D {74 106} KP_Subtract {74 107} KP_Subtract {74 108} KP_Subtract {74 109} KP_Subtract {74 110} KP_Subtract {74 111} KP_Subtract {74 112} KP_Subtract {74 113} KP_Subtract {74 114} Hex_D {74 115} KP_Subtract {74 116} KP_Subtract {74 117} KP_Subtract {74 118} KP_Subtract {74 119} KP_Subtract {74 120} KP_Subtract {74 121} Hex_D {74 122} KP_Subtract {74 123} KP_Subtract {74 124} KP_Subtract {74 125} KP_Subtract {74 126} KP_Subtract {74 127} KP_Subtract {75 0} KP_4 {75 1} KP_4 {75 2} Hex_4 {75 3} KP_4 {75 4} KP_4 {75 5} KP_4 {75 6} KP_4 {75 7} KP_4 {75 8} Ascii_4 {75 9} Hex_4 {75 10} KP_4 {75 11} KP_4 {75 12} KP_4 {75 13} KP_4 {75 14} KP_4 {75 15} KP_4 {75 16} KP_4 {75 17} KP_4 {75 18} Hex_4 {75 19} KP_4 {75 20} KP_4 {75 21} KP_4 {75 22} KP_4 {75 23} KP_4 {75 24} Ascii_4 {75 25} Hex_4 {75 26} KP_4 {75 27} KP_4 {75 28} KP_4 {75 29} KP_4 {75 30} KP_4 {75 31} KP_4 {75 32} KP_4 {75 33} KP_4 {75 34} Hex_4 {75 35} KP_4 {75 36} KP_4 {75 37} KP_4 {75 38} KP_4 {75 39} KP_4 {75 40} Ascii_4 {75 41} Hex_4 {75 42} KP_4 {75 43} KP_4 {75 44} KP_4 {75 45} KP_4 {75 46} KP_4 {75 47} KP_4 {75 48} KP_4 {75 49} KP_4 {75 50} Hex_4 {75 51} KP_4 {75 52} KP_4 {75 53} KP_4 {75 54} KP_4 {75 55} KP_4 {75 56} Ascii_4 {75 57} Hex_4 {75 58} KP_4 {75 59} KP_4 {75 60} KP_4 {75 61} KP_4 {75 62} KP_4 {75 63} KP_4 {75 64} KP_4 {75 65} KP_4 {75 66} Hex_4 {75 67} KP_4 {75 68} KP_4 {75 69} KP_4 {75 70} KP_4 {75 71} KP_4 {75 72} Ascii_4 {75 73} Hex_4 {75 74} KP_4 {75 75} KP_4 {75 76} KP_4 {75 77} KP_4 {75 78} KP_4 {75 79} KP_4 {75 80} KP_4 {75 81} KP_4 {75 82} Hex_4 {75 83} KP_4 {75 84} KP_4 {75 85} KP_4 {75 86} KP_4 {75 87} KP_4 {75 88} Ascii_4 {75 89} Hex_4 {75 90} KP_4 {75 91} KP_4 {75 92} KP_4 {75 93} KP_4 {75 94} KP_4 {75 95} KP_4 {75 96} KP_4 {75 97} KP_4 {75 98} Hex_4 {75 99} KP_4 {75 100} KP_4 {75 101} KP_4 {75 102} KP_4 {75 103} KP_4 {75 104} Ascii_4 {75 105} Hex_4 {75 106} KP_4 {75 107} KP_4 {75 108} KP_4 {75 109} KP_4 {75 110} KP_4 {75 111} KP_4 {75 112} KP_4 {75 113} KP_4 {75 114} Hex_4 {75 115} KP_4 {75 116} KP_4 {75 117} KP_4 {75 118} KP_4 {75 119} KP_4 {75 120} Ascii_4 {75 121} Hex_4 {75 122} KP_4 {75 123} KP_4 {75 124} KP_4 {75 125} KP_4 {75 126} KP_4 {75 127} KP_4 {76 0} KP_5 {76 1} KP_5 {76 2} Hex_5 {76 3} KP_5 {76 4} KP_5 {76 5} KP_5 {76 6} KP_5 {76 7} KP_5 {76 8} Ascii_5 {76 9} Hex_5 {76 10} KP_5 {76 11} KP_5 {76 12} KP_5 {76 13} KP_5 {76 14} KP_5 {76 15} KP_5 {76 16} KP_5 {76 17} KP_5 {76 18} Hex_5 {76 19} KP_5 {76 20} KP_5 {76 21} KP_5 {76 22} KP_5 {76 23} KP_5 {76 24} Ascii_5 {76 25} Hex_5 {76 26} KP_5 {76 27} KP_5 {76 28} KP_5 {76 29} KP_5 {76 30} KP_5 {76 31} KP_5 {76 32} KP_5 {76 33} KP_5 {76 34} Hex_5 {76 35} KP_5 {76 36} KP_5 {76 37} KP_5 {76 38} KP_5 {76 39} KP_5 {76 40} Ascii_5 {76 41} Hex_5 {76 42} KP_5 {76 43} KP_5 {76 44} KP_5 {76 45} KP_5 {76 46} KP_5 {76 47} KP_5 {76 48} KP_5 {76 49} KP_5 {76 50} Hex_5 {76 51} KP_5 {76 52} KP_5 {76 53} KP_5 {76 54} KP_5 {76 55} KP_5 {76 56} Ascii_5 {76 57} Hex_5 {76 58} KP_5 {76 59} KP_5 {76 60} KP_5 {76 61} KP_5 {76 62} KP_5 {76 63} KP_5 {76 64} KP_5 {76 65} KP_5 {76 66} Hex_5 {76 67} KP_5 {76 68} KP_5 {76 69} KP_5 {76 70} KP_5 {76 71} KP_5 {76 72} Ascii_5 {76 73} Hex_5 {76 74} KP_5 {76 75} KP_5 {76 76} KP_5 {76 77} KP_5 {76 78} KP_5 {76 79} KP_5 {76 80} KP_5 {76 81} KP_5 {76 82} Hex_5 {76 83} KP_5 {76 84} KP_5 {76 85} KP_5 {76 86} KP_5 {76 87} KP_5 {76 88} Ascii_5 {76 89} Hex_5 {76 90} KP_5 {76 91} KP_5 {76 92} KP_5 {76 93} KP_5 {76 94} KP_5 {76 95} KP_5 {76 96} KP_5 {76 97} KP_5 {76 98} Hex_5 {76 99} KP_5 {76 100} KP_5 {76 101} KP_5 {76 102} KP_5 {76 103} KP_5 {76 104} Ascii_5 {76 105} Hex_5 {76 106} KP_5 {76 107} KP_5 {76 108} KP_5 {76 109} KP_5 {76 110} KP_5 {76 111} KP_5 {76 112} KP_5 {76 113} KP_5 {76 114} Hex_5 {76 115} KP_5 {76 116} KP_5 {76 117} KP_5 {76 118} KP_5 {76 119} KP_5 {76 120} Ascii_5 {76 121} Hex_5 {76 122} KP_5 {76 123} KP_5 {76 124} KP_5 {76 125} KP_5 {76 126} KP_5 {76 127} KP_5 {77 0} KP_6 {77 1} KP_6 {77 2} Hex_6 {77 3} KP_6 {77 4} KP_6 {77 5} KP_6 {77 6} KP_6 {77 7} KP_6 {77 8} Ascii_6 {77 9} Hex_6 {77 10} KP_6 {77 11} KP_6 {77 12} KP_6 {77 13} KP_6 {77 14} KP_6 {77 15} KP_6 {77 16} KP_6 {77 17} KP_6 {77 18} Hex_6 {77 19} KP_6 {77 20} KP_6 {77 21} KP_6 {77 22} KP_6 {77 23} KP_6 {77 24} Ascii_6 {77 25} Hex_6 {77 26} KP_6 {77 27} KP_6 {77 28} KP_6 {77 29} KP_6 {77 30} KP_6 {77 31} KP_6 {77 32} KP_6 {77 33} KP_6 {77 34} Hex_6 {77 35} KP_6 {77 36} KP_6 {77 37} KP_6 {77 38} KP_6 {77 39} KP_6 {77 40} Ascii_6 {77 41} Hex_6 {77 42} KP_6 {77 43} KP_6 {77 44} KP_6 {77 45} KP_6 {77 46} KP_6 {77 47} KP_6 {77 48} KP_6 {77 49} KP_6 {77 50} Hex_6 {77 51} KP_6 {77 52} KP_6 {77 53} KP_6 {77 54} KP_6 {77 55} KP_6 {77 56} Ascii_6 {77 57} Hex_6 {77 58} KP_6 {77 59} KP_6 {77 60} KP_6 {77 61} KP_6 {77 62} KP_6 {77 63} KP_6 {77 64} KP_6 {77 65} KP_6 {77 66} Hex_6 {77 67} KP_6 {77 68} KP_6 {77 69} KP_6 {77 70} KP_6 {77 71} KP_6 {77 72} Ascii_6 {77 73} Hex_6 {77 74} KP_6 {77 75} KP_6 {77 76} KP_6 {77 77} KP_6 {77 78} KP_6 {77 79} KP_6 {77 80} KP_6 {77 81} KP_6 {77 82} Hex_6 {77 83} KP_6 {77 84} KP_6 {77 85} KP_6 {77 86} KP_6 {77 87} KP_6 {77 88} Ascii_6 {77 89} Hex_6 {77 90} KP_6 {77 91} KP_6 {77 92} KP_6 {77 93} KP_6 {77 94} KP_6 {77 95} KP_6 {77 96} KP_6 {77 97} KP_6 {77 98} Hex_6 {77 99} KP_6 {77 100} KP_6 {77 101} KP_6 {77 102} KP_6 {77 103} KP_6 {77 104} Ascii_6 {77 105} Hex_6 {77 106} KP_6 {77 107} KP_6 {77 108} KP_6 {77 109} KP_6 {77 110} KP_6 {77 111} KP_6 {77 112} KP_6 {77 113} KP_6 {77 114} Hex_6 {77 115} KP_6 {77 116} KP_6 {77 117} KP_6 {77 118} KP_6 {77 119} KP_6 {77 120} Ascii_6 {77 121} Hex_6 {77 122} KP_6 {77 123} KP_6 {77 124} KP_6 {77 125} KP_6 {77 126} KP_6 {77 127} KP_6 {78 0} KP_Add {78 1} KP_Add {78 2} Hex_E {78 3} KP_Add {78 4} KP_Add {78 5} KP_Add {78 6} KP_Add {78 7} KP_Add {78 8} KP_Add {78 9} Hex_E {78 10} KP_Add {78 11} KP_Add {78 12} KP_Add {78 13} KP_Add {78 14} KP_Add {78 15} KP_Add {78 16} KP_Add {78 17} KP_Add {78 18} Hex_E {78 19} KP_Add {78 20} KP_Add {78 21} KP_Add {78 22} KP_Add {78 23} KP_Add {78 24} KP_Add {78 25} Hex_E {78 26} KP_Add {78 27} KP_Add {78 28} KP_Add {78 29} KP_Add {78 30} KP_Add {78 31} KP_Add {78 32} KP_Add {78 33} KP_Add {78 34} Hex_E {78 35} KP_Add {78 36} KP_Add {78 37} KP_Add {78 38} KP_Add {78 39} KP_Add {78 40} KP_Add {78 41} Hex_E {78 42} KP_Add {78 43} KP_Add {78 44} KP_Add {78 45} KP_Add {78 46} KP_Add {78 47} KP_Add {78 48} KP_Add {78 49} KP_Add {78 50} Hex_E {78 51} KP_Add {78 52} KP_Add {78 53} KP_Add {78 54} KP_Add {78 55} KP_Add {78 56} KP_Add {78 57} Hex_E {78 58} KP_Add {78 59} KP_Add {78 60} KP_Add {78 61} KP_Add {78 62} KP_Add {78 63} KP_Add {78 64} KP_Add {78 65} KP_Add {78 66} Hex_E {78 67} KP_Add {78 68} KP_Add {78 69} KP_Add {78 70} KP_Add {78 71} KP_Add {78 72} KP_Add {78 73} Hex_E {78 74} KP_Add {78 75} KP_Add {78 76} KP_Add {78 77} KP_Add {78 78} KP_Add {78 79} KP_Add {78 80} KP_Add {78 81} KP_Add {78 82} Hex_E {78 83} KP_Add {78 84} KP_Add {78 85} KP_Add {78 86} KP_Add {78 87} KP_Add {78 88} KP_Add {78 89} Hex_E {78 90} KP_Add {78 91} KP_Add {78 92} KP_Add {78 93} KP_Add {78 94} KP_Add {78 95} KP_Add {78 96} KP_Add {78 97} KP_Add {78 98} Hex_E {78 99} KP_Add {78 100} KP_Add {78 101} KP_Add {78 102} KP_Add {78 103} KP_Add {78 104} KP_Add {78 105} Hex_E {78 106} KP_Add {78 107} KP_Add {78 108} KP_Add {78 109} KP_Add {78 110} KP_Add {78 111} KP_Add {78 112} KP_Add {78 113} KP_Add {78 114} Hex_E {78 115} KP_Add {78 116} KP_Add {78 117} KP_Add {78 118} KP_Add {78 119} KP_Add {78 120} KP_Add {78 121} Hex_E {78 122} KP_Add {78 123} KP_Add {78 124} KP_Add {78 125} KP_Add {78 126} KP_Add {78 127} KP_Add {79 0} KP_1 {79 1} KP_1 {79 2} Hex_1 {79 3} KP_1 {79 4} KP_1 {79 5} KP_1 {79 6} KP_1 {79 7} KP_1 {79 8} Ascii_1 {79 9} Hex_1 {79 10} KP_1 {79 11} KP_1 {79 12} KP_1 {79 13} KP_1 {79 14} KP_1 {79 15} KP_1 {79 16} KP_1 {79 17} KP_1 {79 18} Hex_1 {79 19} KP_1 {79 20} KP_1 {79 21} KP_1 {79 22} KP_1 {79 23} KP_1 {79 24} Ascii_1 {79 25} Hex_1 {79 26} KP_1 {79 27} KP_1 {79 28} KP_1 {79 29} KP_1 {79 30} KP_1 {79 31} KP_1 {79 32} KP_1 {79 33} KP_1 {79 34} Hex_1 {79 35} KP_1 {79 36} KP_1 {79 37} KP_1 {79 38} KP_1 {79 39} KP_1 {79 40} Ascii_1 {79 41} Hex_1 {79 42} KP_1 {79 43} KP_1 {79 44} KP_1 {79 45} KP_1 {79 46} KP_1 {79 47} KP_1 {79 48} KP_1 {79 49} KP_1 {79 50} Hex_1 {79 51} KP_1 {79 52} KP_1 {79 53} KP_1 {79 54} KP_1 {79 55} KP_1 {79 56} Ascii_1 {79 57} Hex_1 {79 58} KP_1 {79 59} KP_1 {79 60} KP_1 {79 61} KP_1 {79 62} KP_1 {79 63} KP_1 {79 64} KP_1 {79 65} KP_1 {79 66} Hex_1 {79 67} KP_1 {79 68} KP_1 {79 69} KP_1 {79 70} KP_1 {79 71} KP_1 {79 72} Ascii_1 {79 73} Hex_1 {79 74} KP_1 {79 75} KP_1 {79 76} KP_1 {79 77} KP_1 {79 78} KP_1 {79 79} KP_1 {79 80} KP_1 {79 81} KP_1 {79 82} Hex_1 {79 83} KP_1 {79 84} KP_1 {79 85} KP_1 {79 86} KP_1 {79 87} KP_1 {79 88} Ascii_1 {79 89} Hex_1 {79 90} KP_1 {79 91} KP_1 {79 92} KP_1 {79 93} KP_1 {79 94} KP_1 {79 95} KP_1 {79 96} KP_1 {79 97} KP_1 {79 98} Hex_1 {79 99} KP_1 {79 100} KP_1 {79 101} KP_1 {79 102} KP_1 {79 103} KP_1 {79 104} Ascii_1 {79 105} Hex_1 {79 106} KP_1 {79 107} KP_1 {79 108} KP_1 {79 109} KP_1 {79 110} KP_1 {79 111} KP_1 {79 112} KP_1 {79 113} KP_1 {79 114} Hex_1 {79 115} KP_1 {79 116} KP_1 {79 117} KP_1 {79 118} KP_1 {79 119} KP_1 {79 120} Ascii_1 {79 121} Hex_1 {79 122} KP_1 {79 123} KP_1 {79 124} KP_1 {79 125} KP_1 {79 126} KP_1 {79 127} KP_1 {80 0} KP_2 {80 1} KP_2 {80 2} Hex_2 {80 3} KP_2 {80 4} KP_2 {80 5} KP_2 {80 6} KP_2 {80 7} KP_2 {80 8} Ascii_2 {80 9} Hex_2 {80 10} KP_2 {80 11} KP_2 {80 12} KP_2 {80 13} KP_2 {80 14} KP_2 {80 15} KP_2 {80 16} KP_2 {80 17} KP_2 {80 18} Hex_2 {80 19} KP_2 {80 20} KP_2 {80 21} KP_2 {80 22} KP_2 {80 23} KP_2 {80 24} Ascii_2 {80 25} Hex_2 {80 26} KP_2 {80 27} KP_2 {80 28} KP_2 {80 29} KP_2 {80 30} KP_2 {80 31} KP_2 {80 32} KP_2 {80 33} KP_2 {80 34} Hex_2 {80 35} KP_2 {80 36} KP_2 {80 37} KP_2 {80 38} KP_2 {80 39} KP_2 {80 40} Ascii_2 {80 41} Hex_2 {80 42} KP_2 {80 43} KP_2 {80 44} KP_2 {80 45} KP_2 {80 46} KP_2 {80 47} KP_2 {80 48} KP_2 {80 49} KP_2 {80 50} Hex_2 {80 51} KP_2 {80 52} KP_2 {80 53} KP_2 {80 54} KP_2 {80 55} KP_2 {80 56} Ascii_2 {80 57} Hex_2 {80 58} KP_2 {80 59} KP_2 {80 60} KP_2 {80 61} KP_2 {80 62} KP_2 {80 63} KP_2 {80 64} KP_2 {80 65} KP_2 {80 66} Hex_2 {80 67} KP_2 {80 68} KP_2 {80 69} KP_2 {80 70} KP_2 {80 71} KP_2 {80 72} Ascii_2 {80 73} Hex_2 {80 74} KP_2 {80 75} KP_2 {80 76} KP_2 {80 77} KP_2 {80 78} KP_2 {80 79} KP_2 {80 80} KP_2 {80 81} KP_2 {80 82} Hex_2 {80 83} KP_2 {80 84} KP_2 {80 85} KP_2 {80 86} KP_2 {80 87} KP_2 {80 88} Ascii_2 {80 89} Hex_2 {80 90} KP_2 {80 91} KP_2 {80 92} KP_2 {80 93} KP_2 {80 94} KP_2 {80 95} KP_2 {80 96} KP_2 {80 97} KP_2 {80 98} Hex_2 {80 99} KP_2 {80 100} KP_2 {80 101} KP_2 {80 102} KP_2 {80 103} KP_2 {80 104} Ascii_2 {80 105} Hex_2 {80 106} KP_2 {80 107} KP_2 {80 108} KP_2 {80 109} KP_2 {80 110} KP_2 {80 111} KP_2 {80 112} KP_2 {80 113} KP_2 {80 114} Hex_2 {80 115} KP_2 {80 116} KP_2 {80 117} KP_2 {80 118} KP_2 {80 119} KP_2 {80 120} Ascii_2 {80 121} Hex_2 {80 122} KP_2 {80 123} KP_2 {80 124} KP_2 {80 125} KP_2 {80 126} KP_2 {80 127} KP_2 {81 0} KP_3 {81 1} KP_3 {81 2} Hex_3 {81 3} KP_3 {81 4} KP_3 {81 5} KP_3 {81 6} KP_3 {81 7} KP_3 {81 8} Ascii_3 {81 9} Hex_3 {81 10} KP_3 {81 11} KP_3 {81 12} KP_3 {81 13} KP_3 {81 14} KP_3 {81 15} KP_3 {81 16} KP_3 {81 17} KP_3 {81 18} Hex_3 {81 19} KP_3 {81 20} KP_3 {81 21} KP_3 {81 22} KP_3 {81 23} KP_3 {81 24} Ascii_3 {81 25} Hex_3 {81 26} KP_3 {81 27} KP_3 {81 28} KP_3 {81 29} KP_3 {81 30} KP_3 {81 31} KP_3 {81 32} KP_3 {81 33} KP_3 {81 34} Hex_3 {81 35} KP_3 {81 36} KP_3 {81 37} KP_3 {81 38} KP_3 {81 39} KP_3 {81 40} Ascii_3 {81 41} Hex_3 {81 42} KP_3 {81 43} KP_3 {81 44} KP_3 {81 45} KP_3 {81 46} KP_3 {81 47} KP_3 {81 48} KP_3 {81 49} KP_3 {81 50} Hex_3 {81 51} KP_3 {81 52} KP_3 {81 53} KP_3 {81 54} KP_3 {81 55} KP_3 {81 56} Ascii_3 {81 57} Hex_3 {81 58} KP_3 {81 59} KP_3 {81 60} KP_3 {81 61} KP_3 {81 62} KP_3 {81 63} KP_3 {81 64} KP_3 {81 65} KP_3 {81 66} Hex_3 {81 67} KP_3 {81 68} KP_3 {81 69} KP_3 {81 70} KP_3 {81 71} KP_3 {81 72} Ascii_3 {81 73} Hex_3 {81 74} KP_3 {81 75} KP_3 {81 76} KP_3 {81 77} KP_3 {81 78} KP_3 {81 79} KP_3 {81 80} KP_3 {81 81} KP_3 {81 82} Hex_3 {81 83} KP_3 {81 84} KP_3 {81 85} KP_3 {81 86} KP_3 {81 87} KP_3 {81 88} Ascii_3 {81 89} Hex_3 {81 90} KP_3 {81 91} KP_3 {81 92} KP_3 {81 93} KP_3 {81 94} KP_3 {81 95} KP_3 {81 96} KP_3 {81 97} KP_3 {81 98} Hex_3 {81 99} KP_3 {81 100} KP_3 {81 101} KP_3 {81 102} KP_3 {81 103} KP_3 {81 104} Ascii_3 {81 105} Hex_3 {81 106} KP_3 {81 107} KP_3 {81 108} KP_3 {81 109} KP_3 {81 110} KP_3 {81 111} KP_3 {81 112} KP_3 {81 113} KP_3 {81 114} Hex_3 {81 115} KP_3 {81 116} KP_3 {81 117} KP_3 {81 118} KP_3 {81 119} KP_3 {81 120} Ascii_3 {81 121} Hex_3 {81 122} KP_3 {81 123} KP_3 {81 124} KP_3 {81 125} KP_3 {81 126} KP_3 {81 127} KP_3 {82 0} KP_0 {82 1} KP_0 {82 2} Hex_0 {82 3} KP_0 {82 4} KP_0 {82 5} KP_0 {82 6} KP_0 {82 7} KP_0 {82 8} Ascii_0 {82 9} Hex_0 {82 10} KP_0 {82 11} KP_0 {82 12} KP_0 {82 13} KP_0 {82 14} KP_0 {82 15} KP_0 {82 16} KP_0 {82 17} KP_0 {82 18} Hex_0 {82 19} KP_0 {82 20} KP_0 {82 21} KP_0 {82 22} KP_0 {82 23} KP_0 {82 24} Ascii_0 {82 25} Hex_0 {82 26} KP_0 {82 27} KP_0 {82 28} KP_0 {82 29} KP_0 {82 30} KP_0 {82 31} KP_0 {82 32} KP_0 {82 33} KP_0 {82 34} Hex_0 {82 35} KP_0 {82 36} KP_0 {82 37} KP_0 {82 38} KP_0 {82 39} KP_0 {82 40} Ascii_0 {82 41} Hex_0 {82 42} KP_0 {82 43} KP_0 {82 44} KP_0 {82 45} KP_0 {82 46} KP_0 {82 47} KP_0 {82 48} KP_0 {82 49} KP_0 {82 50} Hex_0 {82 51} KP_0 {82 52} KP_0 {82 53} KP_0 {82 54} KP_0 {82 55} KP_0 {82 56} Ascii_0 {82 57} Hex_0 {82 58} KP_0 {82 59} KP_0 {82 60} KP_0 {82 61} KP_0 {82 62} KP_0 {82 63} KP_0 {82 64} KP_0 {82 65} KP_0 {82 66} Hex_0 {82 67} KP_0 {82 68} KP_0 {82 69} KP_0 {82 70} KP_0 {82 71} KP_0 {82 72} Ascii_0 {82 73} Hex_0 {82 74} KP_0 {82 75} KP_0 {82 76} KP_0 {82 77} KP_0 {82 78} KP_0 {82 79} KP_0 {82 80} KP_0 {82 81} KP_0 {82 82} Hex_0 {82 83} KP_0 {82 84} KP_0 {82 85} KP_0 {82 86} KP_0 {82 87} KP_0 {82 88} Ascii_0 {82 89} Hex_0 {82 90} KP_0 {82 91} KP_0 {82 92} KP_0 {82 93} KP_0 {82 94} KP_0 {82 95} KP_0 {82 96} KP_0 {82 97} KP_0 {82 98} Hex_0 {82 99} KP_0 {82 100} KP_0 {82 101} KP_0 {82 102} KP_0 {82 103} KP_0 {82 104} Ascii_0 {82 105} Hex_0 {82 106} KP_0 {82 107} KP_0 {82 108} KP_0 {82 109} KP_0 {82 110} KP_0 {82 111} KP_0 {82 112} KP_0 {82 113} KP_0 {82 114} Hex_0 {82 115} KP_0 {82 116} KP_0 {82 117} KP_0 {82 118} KP_0 {82 119} KP_0 {82 120} Ascii_0 {82 121} Hex_0 {82 122} KP_0 {82 123} KP_0 {82 124} KP_0 {82 125} KP_0 {82 126} KP_0 {82 127} KP_0 {83 0} KP_Period {83 1} KP_Period {83 2} KP_Period {83 3} KP_Period {83 4} KP_Period {83 5} KP_Period {83 6} Boot {83 7} KP_Period {83 8} KP_Period {83 9} KP_Period {83 10} KP_Period {83 11} KP_Period {83 12} Boot {83 13} KP_Period {83 14} Boot {83 15} KP_Period {83 16} KP_Period {83 17} KP_Period {83 18} KP_Period {83 19} KP_Period {83 20} KP_Period {83 21} KP_Period {83 22} Boot {83 23} KP_Period {83 24} KP_Period {83 25} KP_Period {83 26} KP_Period {83 27} KP_Period {83 28} Boot {83 29} KP_Period {83 30} Boot {83 31} KP_Period {83 32} KP_Period {83 33} KP_Period {83 34} KP_Period {83 35} KP_Period {83 36} KP_Period {83 37} KP_Period {83 38} Boot {83 39} KP_Period {83 40} KP_Period {83 41} KP_Period {83 42} KP_Period {83 43} KP_Period {83 44} Boot {83 45} KP_Period {83 46} Boot {83 47} KP_Period {83 48} KP_Period {83 49} KP_Period {83 50} KP_Period {83 51} KP_Period {83 52} KP_Period {83 53} KP_Period {83 54} Boot {83 55} KP_Period {83 56} KP_Period {83 57} KP_Period {83 58} KP_Period {83 59} KP_Period {83 60} Boot {83 61} KP_Period {83 62} Boot {83 63} KP_Period {83 64} KP_Period {83 65} KP_Period {83 66} KP_Period {83 67} KP_Period {83 68} KP_Period {83 69} KP_Period {83 70} Boot {83 71} KP_Period {83 72} KP_Period {83 73} KP_Period {83 74} KP_Period {83 75} KP_Period {83 76} Boot {83 77} KP_Period {83 78} Boot {83 79} KP_Period {83 80} KP_Period {83 81} KP_Period {83 82} KP_Period {83 83} KP_Period {83 84} KP_Period {83 85} KP_Period {83 86} Boot {83 87} KP_Period {83 88} KP_Period {83 89} KP_Period {83 90} KP_Period {83 91} KP_Period {83 92} Boot {83 93} KP_Period {83 94} Boot {83 95} KP_Period {83 96} KP_Period {83 97} KP_Period {83 98} KP_Period {83 99} KP_Period {83 100} KP_Period {83 101} KP_Period {83 102} Boot {83 103} KP_Period {83 104} KP_Period {83 105} KP_Period {83 106} KP_Period {83 107} KP_Period {83 108} Boot {83 109} KP_Period {83 110} Boot {83 111} KP_Period {83 112} KP_Period {83 113} KP_Period {83 114} KP_Period {83 115} KP_Period {83 116} KP_Period {83 117} KP_Period {83 118} Boot {83 119} KP_Period {83 120} KP_Period {83 121} KP_Period {83 122} KP_Period {83 123} KP_Period {83 124} Boot {83 125} KP_Period {83 126} Boot {83 127} KP_Period {84 0} Last_Console {84 1} Last_Console {84 2} Last_Console {84 3} Last_Console {84 4} Last_Console {84 5} Last_Console {84 6} Last_Console {84 7} Last_Console {84 8} Last_Console {84 9} Last_Console {84 10} Last_Console {84 11} Last_Console {84 12} Last_Console {84 13} Last_Console {84 14} Last_Console {84 15} Last_Console {84 16} Last_Console {84 17} Last_Console {84 18} Last_Console {84 19} Last_Console {84 20} Last_Console {84 21} Last_Console {84 22} Last_Console {84 23} Last_Console {84 24} Last_Console {84 25} Last_Console {84 26} Last_Console {84 27} Last_Console {84 28} Last_Console {84 29} Last_Console {84 30} Last_Console {84 31} Last_Console {84 32} Last_Console {84 33} Last_Console {84 34} Last_Console {84 35} Last_Console {84 36} Last_Console {84 37} Last_Console {84 38} Last_Console {84 39} Last_Console {84 40} Last_Console {84 41} Last_Console {84 42} Last_Console {84 43} Last_Console {84 44} Last_Console {84 45} Last_Console {84 46} Last_Console {84 47} Last_Console {84 48} Last_Console {84 49} Last_Console {84 50} Last_Console {84 51} Last_Console {84 52} Last_Console {84 53} Last_Console {84 54} Last_Console {84 55} Last_Console {84 56} Last_Console {84 57} Last_Console {84 58} Last_Console {84 59} Last_Console {84 60} Last_Console {84 61} Last_Console {84 62} Last_Console {84 63} Last_Console {84 64} Last_Console {84 65} Last_Console {84 66} Last_Console {84 67} Last_Console {84 68} Last_Console {84 69} Last_Console {84 70} Last_Console {84 71} Last_Console {84 72} Last_Console {84 73} Last_Console {84 74} Last_Console {84 75} Last_Console {84 76} Last_Console {84 77} Last_Console {84 78} Last_Console {84 79} Last_Console {84 80} Last_Console {84 81} Last_Console {84 82} Last_Console {84 83} Last_Console {84 84} Last_Console {84 85} Last_Console {84 86} Last_Console {84 87} Last_Console {84 88} Last_Console {84 89} Last_Console {84 90} Last_Console {84 91} Last_Console {84 92} Last_Console {84 93} Last_Console {84 94} Last_Console {84 95} Last_Console {84 96} Last_Console {84 97} Last_Console {84 98} Last_Console {84 99} Last_Console {84 100} Last_Console {84 101} Last_Console {84 102} Last_Console {84 103} Last_Console {84 104} Last_Console {84 105} Last_Console {84 106} Last_Console {84 107} Last_Console {84 108} Last_Console {84 109} Last_Console {84 110} Last_Console {84 111} Last_Console {84 112} Last_Console {84 113} Last_Console {84 114} Last_Console {84 115} Last_Console {84 116} Last_Console {84 117} Last_Console {84 118} Last_Console {84 119} Last_Console {84 120} Last_Console {84 121} Last_Console {84 122} Last_Console {84 123} Last_Console {84 124} Last_Console {84 125} Last_Console {84 126} Last_Console {84 127} Last_Console {86 0} less {86 1} greater {86 2} bar {86 3} brokenbar {86 4} Control_backslash {86 5} greater {86 6} Control_backslash {86 7} Control_backslash {86 8} Meta_less {86 9} Meta_greater {86 10} Meta_bar {86 11} Meta_bar {86 12} Meta_Control_backslash {86 13} Meta_greater {86 14} Meta_Control_backslash {86 15} Meta_Control_backslash {86 16} less {86 17} greater {86 18} bar {86 19} brokenbar {86 20} Control_backslash {86 21} greater {86 22} Control_backslash {86 23} Control_backslash {86 24} Meta_less {86 25} Meta_greater {86 26} Meta_bar {86 27} Meta_bar {86 28} Meta_Control_backslash {86 29} Meta_greater {86 30} Meta_Control_backslash {86 31} Meta_Control_backslash {86 32} less {86 33} greater {86 34} bar {86 35} brokenbar {86 36} Control_backslash {86 37} greater {86 38} Control_backslash {86 39} Control_backslash {86 40} Meta_less {86 41} Meta_greater {86 42} Meta_bar {86 43} Meta_bar {86 44} Meta_Control_backslash {86 45} Meta_greater {86 46} Meta_Control_backslash {86 47} Meta_Control_backslash {86 48} less {86 49} greater {86 50} bar {86 51} brokenbar {86 52} Control_backslash {86 53} greater {86 54} Control_backslash {86 55} Control_backslash {86 56} Meta_less {86 57} Meta_greater {86 58} Meta_bar {86 59} Meta_bar {86 60} Meta_Control_backslash {86 61} Meta_greater {86 62} Meta_Control_backslash {86 63} Meta_Control_backslash {86 64} less {86 65} greater {86 66} bar {86 67} brokenbar {86 68} Control_backslash {86 69} greater {86 70} Control_backslash {86 71} Control_backslash {86 72} Meta_less {86 73} Meta_greater {86 74} Meta_bar {86 75} Meta_bar {86 76} Meta_Control_backslash {86 77} Meta_greater {86 78} Meta_Control_backslash {86 79} Meta_Control_backslash {86 80} less {86 81} greater {86 82} bar {86 83} brokenbar {86 84} Control_backslash {86 85} greater {86 86} Control_backslash {86 87} Control_backslash {86 88} Meta_less {86 89} Meta_greater {86 90} Meta_bar {86 91} Meta_bar {86 92} Meta_Control_backslash {86 93} Meta_greater {86 94} Meta_Control_backslash {86 95} Meta_Control_backslash {86 96} less {86 97} greater {86 98} bar {86 99} brokenbar {86 100} Control_backslash {86 101} greater {86 102} Control_backslash {86 103} Control_backslash {86 104} Meta_less {86 105} Meta_greater {86 106} Meta_bar {86 107} Meta_bar {86 108} Meta_Control_backslash {86 109} Meta_greater {86 110} Meta_Control_backslash {86 111} Meta_Control_backslash {86 112} less {86 113} greater {86 114} bar {86 115} brokenbar {86 116} Control_backslash {86 117} greater {86 118} Control_backslash {86 119} Control_backslash {86 120} Meta_less {86 121} Meta_greater {86 122} Meta_bar {86 123} Meta_bar {86 124} Meta_Control_backslash {86 125} Meta_greater {86 126} Meta_Control_backslash {86 127} Meta_Control_backslash {87 0} F11 {87 1} F23 {87 2} Console_23 {87 3} Console_35 {87 4} F35 {87 5} F47 {87 6} Console_23 {87 7} Console_35 {87 8} Console_11 {87 9} Console_23 {87 10} F11 {87 11} F11 {87 12} Console_11 {87 13} Console_23 {87 14} F11 {87 15} F11 {87 16} F11 {87 17} F23 {87 18} Console_23 {87 19} Console_35 {87 20} F35 {87 21} F47 {87 22} Console_23 {87 23} Console_35 {87 24} Console_11 {87 25} Console_23 {87 26} F11 {87 27} F11 {87 28} Console_11 {87 29} Console_23 {87 30} F11 {87 31} F11 {87 32} F11 {87 33} F23 {87 34} Console_23 {87 35} Console_35 {87 36} F35 {87 37} F47 {87 38} Console_23 {87 39} Console_35 {87 40} Console_11 {87 41} Console_23 {87 42} F11 {87 43} F11 {87 44} Console_11 {87 45} Console_23 {87 46} F11 {87 47} F11 {87 48} F11 {87 49} F23 {87 50} Console_23 {87 51} Console_35 {87 52} F35 {87 53} F47 {87 54} Console_23 {87 55} Console_35 {87 56} Console_11 {87 57} Console_23 {87 58} F11 {87 59} F11 {87 60} Console_11 {87 61} Console_23 {87 62} F11 {87 63} F11 {87 64} F11 {87 65} F23 {87 66} Console_23 {87 67} Console_35 {87 68} F35 {87 69} F47 {87 70} Console_23 {87 71} Console_35 {87 72} Console_11 {87 73} Console_23 {87 74} F11 {87 75} F11 {87 76} Console_11 {87 77} Console_23 {87 78} F11 {87 79} F11 {87 80} F11 {87 81} F23 {87 82} Console_23 {87 83} Console_35 {87 84} F35 {87 85} F47 {87 86} Console_23 {87 87} Console_35 {87 88} Console_11 {87 89} Console_23 {87 90} F11 {87 91} F11 {87 92} Console_11 {87 93} Console_23 {87 94} F11 {87 95} F11 {87 96} F11 {87 97} F23 {87 98} Console_23 {87 99} Console_35 {87 100} F35 {87 101} F47 {87 102} Console_23 {87 103} Console_35 {87 104} Console_11 {87 105} Console_23 {87 106} F11 {87 107} F11 {87 108} Console_11 {87 109} Console_23 {87 110} F11 {87 111} F11 {87 112} F11 {87 113} F23 {87 114} Console_23 {87 115} Console_35 {87 116} F35 {87 117} F47 {87 118} Console_23 {87 119} Console_35 {87 120} Console_11 {87 121} Console_23 {87 122} F11 {87 123} F11 {87 124} Console_11 {87 125} Console_23 {87 126} F11 {87 127} F11 {88 0} F12 {88 1} F24 {88 2} Console_24 {88 3} Console_36 {88 4} F36 {88 5} F48 {88 6} Console_24 {88 7} Console_36 {88 8} Console_12 {88 9} Console_24 {88 10} F12 {88 11} F12 {88 12} Console_12 {88 13} Console_24 {88 14} F12 {88 15} F12 {88 16} F12 {88 17} F24 {88 18} Console_24 {88 19} Console_36 {88 20} F36 {88 21} F48 {88 22} Console_24 {88 23} Console_36 {88 24} Console_12 {88 25} Console_24 {88 26} F12 {88 27} F12 {88 28} Console_12 {88 29} Console_24 {88 30} F12 {88 31} F12 {88 32} F12 {88 33} F24 {88 34} Console_24 {88 35} Console_36 {88 36} F36 {88 37} F48 {88 38} Console_24 {88 39} Console_36 {88 40} Console_12 {88 41} Console_24 {88 42} F12 {88 43} F12 {88 44} Console_12 {88 45} Console_24 {88 46} F12 {88 47} F12 {88 48} F12 {88 49} F24 {88 50} Console_24 {88 51} Console_36 {88 52} F36 {88 53} F48 {88 54} Console_24 {88 55} Console_36 {88 56} Console_12 {88 57} Console_24 {88 58} F12 {88 59} F12 {88 60} Console_12 {88 61} Console_24 {88 62} F12 {88 63} F12 {88 64} F12 {88 65} F24 {88 66} Console_24 {88 67} Console_36 {88 68} F36 {88 69} F48 {88 70} Console_24 {88 71} Console_36 {88 72} Console_12 {88 73} Console_24 {88 74} F12 {88 75} F12 {88 76} Console_12 {88 77} Console_24 {88 78} F12 {88 79} F12 {88 80} F12 {88 81} F24 {88 82} Console_24 {88 83} Console_36 {88 84} F36 {88 85} F48 {88 86} Console_24 {88 87} Console_36 {88 88} Console_12 {88 89} Console_24 {88 90} F12 {88 91} F12 {88 92} Console_12 {88 93} Console_24 {88 94} F12 {88 95} F12 {88 96} F12 {88 97} F24 {88 98} Console_24 {88 99} Console_36 {88 100} F36 {88 101} F48 {88 102} Console_24 {88 103} Console_36 {88 104} Console_12 {88 105} Console_24 {88 106} F12 {88 107} F12 {88 108} Console_12 {88 109} Console_24 {88 110} F12 {88 111} F12 {88 112} F12 {88 113} F24 {88 114} Console_24 {88 115} Console_36 {88 116} F36 {88 117} F48 {88 118} Console_24 {88 119} Console_36 {88 120} Console_12 {88 121} Console_24 {88 122} F12 {88 123} F12 {88 124} Console_12 {88 125} Console_24 {88 126} F12 {88 127} F12 {96 0} KP_Enter {96 1} KP_Enter {96 2} Hex_F {96 3} KP_Enter {96 4} KP_Enter {96 5} KP_Enter {96 6} KP_Enter {96 7} KP_Enter {96 8} KP_Enter {96 9} Hex_F {96 10} KP_Enter {96 11} KP_Enter {96 12} KP_Enter {96 13} KP_Enter {96 14} KP_Enter {96 15} KP_Enter {96 16} KP_Enter {96 17} KP_Enter {96 18} Hex_F {96 19} KP_Enter {96 20} KP_Enter {96 21} KP_Enter {96 22} KP_Enter {96 23} KP_Enter {96 24} KP_Enter {96 25} Hex_F {96 26} KP_Enter {96 27} KP_Enter {96 28} KP_Enter {96 29} KP_Enter {96 30} KP_Enter {96 31} KP_Enter {96 32} KP_Enter {96 33} KP_Enter {96 34} Hex_F {96 35} KP_Enter {96 36} KP_Enter {96 37} KP_Enter {96 38} KP_Enter {96 39} KP_Enter {96 40} KP_Enter {96 41} Hex_F {96 42} KP_Enter {96 43} KP_Enter {96 44} KP_Enter {96 45} KP_Enter {96 46} KP_Enter {96 47} KP_Enter {96 48} KP_Enter {96 49} KP_Enter {96 50} Hex_F {96 51} KP_Enter {96 52} KP_Enter {96 53} KP_Enter {96 54} KP_Enter {96 55} KP_Enter {96 56} KP_Enter {96 57} Hex_F {96 58} KP_Enter {96 59} KP_Enter {96 60} KP_Enter {96 61} KP_Enter {96 62} KP_Enter {96 63} KP_Enter {96 64} KP_Enter {96 65} KP_Enter {96 66} Hex_F {96 67} KP_Enter {96 68} KP_Enter {96 69} KP_Enter {96 70} KP_Enter {96 71} KP_Enter {96 72} KP_Enter {96 73} Hex_F {96 74} KP_Enter {96 75} KP_Enter {96 76} KP_Enter {96 77} KP_Enter {96 78} KP_Enter {96 79} KP_Enter {96 80} KP_Enter {96 81} KP_Enter {96 82} Hex_F {96 83} KP_Enter {96 84} KP_Enter {96 85} KP_Enter {96 86} KP_Enter {96 87} KP_Enter {96 88} KP_Enter {96 89} Hex_F {96 90} KP_Enter {96 91} KP_Enter {96 92} KP_Enter {96 93} KP_Enter {96 94} KP_Enter {96 95} KP_Enter {96 96} KP_Enter {96 97} KP_Enter {96 98} Hex_F {96 99} KP_Enter {96 100} KP_Enter {96 101} KP_Enter {96 102} KP_Enter {96 103} KP_Enter {96 104} KP_Enter {96 105} Hex_F {96 106} KP_Enter {96 107} KP_Enter {96 108} KP_Enter {96 109} KP_Enter {96 110} KP_Enter {96 111} KP_Enter {96 112} KP_Enter {96 113} KP_Enter {96 114} Hex_F {96 115} KP_Enter {96 116} KP_Enter {96 117} KP_Enter {96 118} KP_Enter {96 119} KP_Enter {96 120} KP_Enter {96 121} Hex_F {96 122} KP_Enter {96 123} KP_Enter {96 124} KP_Enter {96 125} KP_Enter {96 126} KP_Enter {96 127} KP_Enter {97 0} Control {97 1} Control {97 2} Control {97 3} Control {97 4} Control {97 5} Control {97 6} Control {97 7} Control {97 8} Control {97 9} Control {97 10} Control {97 11} Control {97 12} Control {97 13} Control {97 14} Control {97 15} Control {97 16} Control {97 17} Control {97 18} Control {97 19} Control {97 20} Control {97 21} Control {97 22} Control {97 23} Control {97 24} Control {97 25} Control {97 26} Control {97 27} Control {97 28} Control {97 29} Control {97 30} Control {97 31} Control {97 32} Control {97 33} Control {97 34} Control {97 35} Control {97 36} Control {97 37} Control {97 38} Control {97 39} Control {97 40} Control {97 41} Control {97 42} Control {97 43} Control {97 44} Control {97 45} Control {97 46} Control {97 47} Control {97 48} Control {97 49} Control {97 50} Control {97 51} Control {97 52} Control {97 53} Control {97 54} Control {97 55} Control {97 56} Control {97 57} Control {97 58} Control {97 59} Control {97 60} Control {97 61} Control {97 62} Control {97 63} Control {97 64} Control {97 65} Control {97 66} Control {97 67} Control {97 68} Control {97 69} Control {97 70} Control {97 71} Control {97 72} Control {97 73} Control {97 74} Control {97 75} Control {97 76} Control {97 77} Control {97 78} Control {97 79} Control {97 80} Control {97 81} Control {97 82} Control {97 83} Control {97 84} Control {97 85} Control {97 86} Control {97 87} Control {97 88} Control {97 89} Control {97 90} Control {97 91} Control {97 92} Control {97 93} Control {97 94} Control {97 95} Control {97 96} Control {97 97} Control {97 98} Control {97 99} Control {97 100} Control {97 101} Control {97 102} Control {97 103} Control {97 104} Control {97 105} Control {97 106} Control {97 107} Control {97 108} Control {97 109} Control {97 110} Control {97 111} Control {97 112} Control {97 113} Control {97 114} Control {97 115} Control {97 116} Control {97 117} Control {97 118} Control {97 119} Control {97 120} Control {97 121} Control {97 122} Control {97 123} Control {97 124} Control {97 125} Control {97 126} Control {97 127} Control {98 0} KP_Divide {98 1} KP_Divide {98 2} Hex_B {98 3} KP_Divide {98 4} KP_Divide {98 5} KP_Divide {98 6} KP_Divide {98 7} KP_Divide {98 8} KP_Divide {98 9} Hex_B {98 10} KP_Divide {98 11} KP_Divide {98 12} KP_Divide {98 13} KP_Divide {98 14} KP_Divide {98 15} KP_Divide {98 16} KP_Divide {98 17} KP_Divide {98 18} Hex_B {98 19} KP_Divide {98 20} KP_Divide {98 21} KP_Divide {98 22} KP_Divide {98 23} KP_Divide {98 24} KP_Divide {98 25} Hex_B {98 26} KP_Divide {98 27} KP_Divide {98 28} KP_Divide {98 29} KP_Divide {98 30} KP_Divide {98 31} KP_Divide {98 32} KP_Divide {98 33} KP_Divide {98 34} Hex_B {98 35} KP_Divide {98 36} KP_Divide {98 37} KP_Divide {98 38} KP_Divide {98 39} KP_Divide {98 40} KP_Divide {98 41} Hex_B {98 42} KP_Divide {98 43} KP_Divide {98 44} KP_Divide {98 45} KP_Divide {98 46} KP_Divide {98 47} KP_Divide {98 48} KP_Divide {98 49} KP_Divide {98 50} Hex_B {98 51} KP_Divide {98 52} KP_Divide {98 53} KP_Divide {98 54} KP_Divide {98 55} KP_Divide {98 56} KP_Divide {98 57} Hex_B {98 58} KP_Divide {98 59} KP_Divide {98 60} KP_Divide {98 61} KP_Divide {98 62} KP_Divide {98 63} KP_Divide {98 64} KP_Divide {98 65} KP_Divide {98 66} Hex_B {98 67} KP_Divide {98 68} KP_Divide {98 69} KP_Divide {98 70} KP_Divide {98 71} KP_Divide {98 72} KP_Divide {98 73} Hex_B {98 74} KP_Divide {98 75} KP_Divide {98 76} KP_Divide {98 77} KP_Divide {98 78} KP_Divide {98 79} KP_Divide {98 80} KP_Divide {98 81} KP_Divide {98 82} Hex_B {98 83} KP_Divide {98 84} KP_Divide {98 85} KP_Divide {98 86} KP_Divide {98 87} KP_Divide {98 88} KP_Divide {98 89} Hex_B {98 90} KP_Divide {98 91} KP_Divide {98 92} KP_Divide {98 93} KP_Divide {98 94} KP_Divide {98 95} KP_Divide {98 96} KP_Divide {98 97} KP_Divide {98 98} Hex_B {98 99} KP_Divide {98 100} KP_Divide {98 101} KP_Divide {98 102} KP_Divide {98 103} KP_Divide {98 104} KP_Divide {98 105} Hex_B {98 106} KP_Divide {98 107} KP_Divide {98 108} KP_Divide {98 109} KP_Divide {98 110} KP_Divide {98 111} KP_Divide {98 112} KP_Divide {98 113} KP_Divide {98 114} Hex_B {98 115} KP_Divide {98 116} KP_Divide {98 117} KP_Divide {98 118} KP_Divide {98 119} KP_Divide {98 120} KP_Divide {98 121} Hex_B {98 122} KP_Divide {98 123} KP_Divide {98 124} KP_Divide {98 125} KP_Divide {98 126} KP_Divide {98 127} KP_Divide {99 0} Control_backslash {99 1} Control_backslash {99 2} Control_backslash {99 3} Control_backslash {99 4} Control_backslash {99 5} Control_backslash {99 6} Last_Console {99 7} Last_Console {99 8} Last_Console {99 9} Last_Console {99 10} Meta_Control_backslash {99 11} Meta_Control_backslash {99 12} Meta_Control_backslash {99 13} Meta_Control_backslash {99 14} Control_backslash {99 15} Control_backslash {99 16} Control_backslash {99 17} Control_backslash {99 18} Control_backslash {99 19} Control_backslash {99 20} Last_Console {99 21} Last_Console {99 22} Last_Console {99 23} Last_Console {99 24} Meta_Control_backslash {99 25} Meta_Control_backslash {99 26} Meta_Control_backslash {99 27} Meta_Control_backslash {99 28} Control_backslash {99 29} Control_backslash {99 30} Control_backslash {99 31} Control_backslash {99 32} Control_backslash {99 33} Control_backslash {99 34} Last_Console {99 35} Last_Console {99 36} Last_Console {99 37} Last_Console {99 38} Meta_Control_backslash {99 39} Meta_Control_backslash {99 40} Meta_Control_backslash {99 41} Meta_Control_backslash {99 42} Control_backslash {99 43} Control_backslash {99 44} Control_backslash {99 45} Control_backslash {99 46} Control_backslash {99 47} Control_backslash {99 48} Last_Console {99 49} Last_Console {99 50} Last_Console {99 51} Last_Console {99 52} Meta_Control_backslash {99 53} Meta_Control_backslash {99 54} Meta_Control_backslash {99 55} Meta_Control_backslash {99 56} Control_backslash {99 57} Control_backslash {99 58} Control_backslash {99 59} Control_backslash {99 60} Control_backslash {99 61} Control_backslash {99 62} Last_Console {99 63} Last_Console {99 64} Last_Console {99 65} Last_Console {99 66} Meta_Control_backslash {99 67} Meta_Control_backslash {99 68} Meta_Control_backslash {99 69} Meta_Control_backslash {99 70} Control_backslash {99 71} Control_backslash {99 72} Control_backslash {99 73} Control_backslash {99 74} Control_backslash {99 75} Control_backslash {99 76} Last_Console {99 77} Last_Console {99 78} Last_Console {99 79} Last_Console {99 80} Meta_Control_backslash {99 81} Meta_Control_backslash {99 82} Meta_Control_backslash {99 83} Meta_Control_backslash {99 84} Control_backslash {99 85} Control_backslash {99 86} Control_backslash {99 87} Control_backslash {99 88} Control_backslash {99 89} Control_backslash {99 90} Last_Console {99 91} Last_Console {99 92} Last_Console {99 93} Last_Console {99 94} Meta_Control_backslash {99 95} Meta_Control_backslash {99 96} Meta_Control_backslash {99 97} Meta_Control_backslash {99 98} Control_backslash {99 99} Control_backslash {99 100} Control_backslash {99 101} Control_backslash {99 102} Control_backslash {99 103} Control_backslash {99 104} Last_Console {99 105} Last_Console {99 106} Last_Console {99 107} Last_Console {99 108} Meta_Control_backslash {99 109} Meta_Control_backslash {99 110} Meta_Control_backslash {99 111} Meta_Control_backslash {100 0} Alt {100 1} Alt {100 2} Alt {100 3} Alt {100 4} Alt {100 5} Alt {100 6} Alt {100 7} Alt {100 8} Alt {100 9} Alt {100 10} Alt {100 11} Alt {100 12} Alt {100 13} Alt {100 14} Alt {100 15} Alt {100 16} Alt {100 17} Alt {100 18} Alt {100 19} Alt {100 20} Alt {100 21} Alt {100 22} Alt {100 23} Alt {100 24} Alt {100 25} Alt {100 26} Alt {100 27} Alt {100 28} Alt {100 29} Alt {100 30} Alt {100 31} Alt {100 32} Alt {100 33} Alt {100 34} Alt {100 35} Alt {100 36} Alt {100 37} Alt {100 38} Alt {100 39} Alt {100 40} Alt {100 41} Alt {100 42} Alt {100 43} Alt {100 44} Alt {100 45} Alt {100 46} Alt {100 47} Alt {100 48} Alt {100 49} Alt {100 50} Alt {100 51} Alt {100 52} Alt {100 53} Alt {100 54} Alt {100 55} Alt {100 56} Alt {100 57} Alt {100 58} Alt {100 59} Alt {100 60} Alt {100 61} Alt {100 62} Alt {100 63} Alt {100 64} Alt {100 65} Alt {100 66} Alt {100 67} Alt {100 68} Alt {100 69} Alt {100 70} Alt {100 71} Alt {100 72} Alt {100 73} Alt {100 74} Alt {100 75} Alt {100 76} Alt {100 77} Alt {100 78} Alt {100 79} Alt {100 80} Alt {100 81} Alt {100 82} Alt {100 83} Alt {100 84} Alt {100 85} Alt {100 86} Alt {100 87} Alt {100 88} Alt {100 89} Alt {100 90} Alt {100 91} Alt {100 92} Alt {100 93} Alt {100 94} Alt {100 95} Alt {100 96} Alt {100 97} Alt {100 98} Alt {100 99} Alt {100 100} Alt {100 101} Alt {100 102} Alt {100 103} Alt {100 104} Alt {100 105} Alt {100 106} Alt {100 107} Alt {100 108} Alt {100 109} Alt {100 110} Alt {100 111} Alt {100 112} Alt {100 113} Alt {100 114} Alt {100 115} Alt {100 116} Alt {100 117} Alt {100 118} Alt {100 119} Alt {100 120} Alt {100 121} Alt {100 122} Alt {100 123} Alt {100 124} Alt {100 125} Alt {100 126} Alt {100 127} Alt {101 0} Break {101 1} Break {101 2} Break {101 3} Break {101 4} Break {101 5} Break {101 6} Break {101 7} Break {101 8} Break {101 9} Break {101 10} Break {101 11} Break {101 12} Break {101 13} Break {101 14} Break {101 15} Break {101 16} Break {101 17} Break {101 18} Break {101 19} Break {101 20} Break {101 21} Break {101 22} Break {101 23} Break {101 24} Break {101 25} Break {101 26} Break {101 27} Break {101 28} Break {101 29} Break {101 30} Break {101 31} Break {101 32} Break {101 33} Break {101 34} Break {101 35} Break {101 36} Break {101 37} Break {101 38} Break {101 39} Break {101 40} Break {101 41} Break {101 42} Break {101 43} Break {101 44} Break {101 45} Break {101 46} Break {101 47} Break {101 48} Break {101 49} Break {101 50} Break {101 51} Break {101 52} Break {101 53} Break {101 54} Break {101 55} Break {101 56} Break {101 57} Break {101 58} Break {101 59} Break {101 60} Break {101 61} Break {101 62} Break {101 63} Break {101 64} Break {101 65} Break {101 66} Break {101 67} Break {101 68} Break {101 69} Break {101 70} Break {101 71} Break {101 72} Break {101 73} Break {101 74} Break {101 75} Break {101 76} Break {101 77} Break {101 78} Break {101 79} Break {101 80} Break {101 81} Break {101 82} Break {101 83} Break {101 84} Break {101 85} Break {101 86} Break {101 87} Break {101 88} Break {101 89} Break {101 90} Break {101 91} Break {101 92} Break {101 93} Break {101 94} Break {101 95} Break {101 96} Break {101 97} Break {101 98} Break {101 99} Break {101 100} Break {101 101} Break {101 102} Break {101 103} Break {101 104} Break {101 105} Break {101 106} Break {101 107} Break {101 108} Break {101 109} Break {101 110} Break {101 111} Break {101 112} Break {101 113} Break {101 114} Break {101 115} Break {101 116} Break {101 117} Break {101 118} Break {101 119} Break {101 120} Break {101 121} Break {101 122} Break {101 123} Break {101 124} Break {101 125} Break {101 126} Break {101 127} Break {102 0} Find {102 1} Find {102 2} Find {102 3} Find {102 4} Find {102 5} Find {102 6} Find {102 7} Find {102 8} Find {102 9} Find {102 10} Find {102 11} Find {102 12} Find {102 13} Find {102 14} Find {102 15} Find {102 16} Find {102 17} Find {102 18} Find {102 19} Find {102 20} Find {102 21} Find {102 22} Find {102 23} Find {102 24} Find {102 25} Find {102 26} Find {102 27} Find {102 28} Find {102 29} Find {102 30} Find {102 31} Find {102 32} Find {102 33} Find {102 34} Find {102 35} Find {102 36} Find {102 37} Find {102 38} Find {102 39} Find {102 40} Find {102 41} Find {102 42} Find {102 43} Find {102 44} Find {102 45} Find {102 46} Find {102 47} Find {102 48} Find {102 49} Find {102 50} Find {102 51} Find {102 52} Find {102 53} Find {102 54} Find {102 55} Find {102 56} Find {102 57} Find {102 58} Find {102 59} Find {102 60} Find {102 61} Find {102 62} Find {102 63} Find {102 64} Find {102 65} Find {102 66} Find {102 67} Find {102 68} Find {102 69} Find {102 70} Find {102 71} Find {102 72} Find {102 73} Find {102 74} Find {102 75} Find {102 76} Find {102 77} Find {102 78} Find {102 79} Find {102 80} Find {102 81} Find {102 82} Find {102 83} Find {102 84} Find {102 85} Find {102 86} Find {102 87} Find {102 88} Find {102 89} Find {102 90} Find {102 91} Find {102 92} Find {102 93} Find {102 94} Find {102 95} Find {102 96} Find {102 97} Find {102 98} Find {102 99} Find {102 100} Find {102 101} Find {102 102} Find {102 103} Find {102 104} Find {102 105} Find {102 106} Find {102 107} Find {102 108} Find {102 109} Find {102 110} Find {102 111} Find {102 112} Find {102 113} Find {102 114} Find {102 115} Find {102 116} Find {102 117} Find {102 118} Find {102 119} Find {102 120} Find {102 121} Find {102 122} Find {102 123} Find {102 124} Find {102 125} Find {102 126} Find {102 127} Find {103 0} Up {103 1} Up {103 2} Up {103 3} Up {103 4} Up {103 5} Up {103 6} Up {103 7} Up {103 8} KeyboardSignal {103 9} Up {103 10} Up {103 11} Up {103 12} Up {103 13} Up {103 14} Up {103 15} Up {103 16} Up {103 17} Up {103 18} Up {103 19} Up {103 20} Up {103 21} Up {103 22} Up {103 23} Up {103 24} KeyboardSignal {103 25} Up {103 26} Up {103 27} Up {103 28} Up {103 29} Up {103 30} Up {103 31} Up {103 32} Up {103 33} Up {103 34} Up {103 35} Up {103 36} Up {103 37} Up {103 38} Up {103 39} Up {103 40} KeyboardSignal {103 41} Up {103 42} Up {103 43} Up {103 44} Up {103 45} Up {103 46} Up {103 47} Up {103 48} Up {103 49} Up {103 50} Up {103 51} Up {103 52} Up {103 53} Up {103 54} Up {103 55} Up {103 56} KeyboardSignal {103 57} Up {103 58} Up {103 59} Up {103 60} Up {103 61} Up {103 62} Up {103 63} Up {103 64} Up {103 65} Up {103 66} Up {103 67} Up {103 68} Up {103 69} Up {103 70} Up {103 71} Up {103 72} KeyboardSignal {103 73} Up {103 74} Up {103 75} Up {103 76} Up {103 77} Up {103 78} Up {103 79} Up {103 80} Up {103 81} Up {103 82} Up {103 83} Up {103 84} Up {103 85} Up {103 86} Up {103 87} Up {103 88} KeyboardSignal {103 89} Up {103 90} Up {103 91} Up {103 92} Up {103 93} Up {103 94} Up {103 95} Up {103 96} Up {103 97} Up {103 98} Up {103 99} Up {103 100} Up {103 101} Up {103 102} Up {103 103} Up {103 104} KeyboardSignal {103 105} Up {103 106} Up {103 107} Up {103 108} Up {103 109} Up {103 110} Up {103 111} Up {103 112} Up {103 113} Up {103 114} Up {103 115} Up {103 116} Up {103 117} Up {103 118} Up {103 119} Up {103 120} KeyboardSignal {103 121} Up {103 122} Up {103 123} Up {103 124} Up {103 125} Up {103 126} Up {103 127} Up {104 0} Prior {104 1} Scroll_Backward {104 2} Prior {104 3} Prior {104 4} Prior {104 5} Prior {104 6} Prior {104 7} Prior {104 8} Prior {104 9} Prior {104 10} Prior {104 11} Prior {104 12} Prior {104 13} Prior {104 14} Prior {104 15} Prior {104 16} Prior {104 17} Scroll_Backward {104 18} Prior {104 19} Prior {104 20} Prior {104 21} Prior {104 22} Prior {104 23} Prior {104 24} Prior {104 25} Prior {104 26} Prior {104 27} Prior {104 28} Prior {104 29} Prior {104 30} Prior {104 31} Prior {104 32} Prior {104 33} Scroll_Backward {104 34} Prior {104 35} Prior {104 36} Prior {104 37} Prior {104 38} Prior {104 39} Prior {104 40} Prior {104 41} Prior {104 42} Prior {104 43} Prior {104 44} Prior {104 45} Prior {104 46} Prior {104 47} Prior {104 48} Prior {104 49} Scroll_Backward {104 50} Prior {104 51} Prior {104 52} Prior {104 53} Prior {104 54} Prior {104 55} Prior {104 56} Prior {104 57} Prior {104 58} Prior {104 59} Prior {104 60} Prior {104 61} Prior {104 62} Prior {104 63} Prior {104 64} Prior {104 65} Scroll_Backward {104 66} Prior {104 67} Prior {104 68} Prior {104 69} Prior {104 70} Prior {104 71} Prior {104 72} Prior {104 73} Prior {104 74} Prior {104 75} Prior {104 76} Prior {104 77} Prior {104 78} Prior {104 79} Prior {104 80} Prior {104 81} Scroll_Backward {104 82} Prior {104 83} Prior {104 84} Prior {104 85} Prior {104 86} Prior {104 87} Prior {104 88} Prior {104 89} Prior {104 90} Prior {104 91} Prior {104 92} Prior {104 93} Prior {104 94} Prior {104 95} Prior {104 96} Prior {104 97} Scroll_Backward {104 98} Prior {104 99} Prior {104 100} Prior {104 101} Prior {104 102} Prior {104 103} Prior {104 104} Prior {104 105} Prior {104 106} Prior {104 107} Prior {104 108} Prior {104 109} Prior {104 110} Prior {104 111} Prior {104 112} Prior {104 113} Scroll_Backward {104 114} Prior {104 115} Prior {104 116} Prior {104 117} Prior {104 118} Prior {104 119} Prior {104 120} Prior {104 121} Prior {104 122} Prior {104 123} Prior {104 124} Prior {104 125} Prior {104 126} Prior {104 127} Prior {105 0} Left {105 1} Left {105 2} Left {105 3} Left {105 4} Left {105 5} Left {105 6} Left {105 7} Left {105 8} Decr_Console {105 9} Left {105 10} Left {105 11} Left {105 12} Left {105 13} Left {105 14} Left {105 15} Left {105 16} Left {105 17} Left {105 18} Left {105 19} Left {105 20} Left {105 21} Left {105 22} Left {105 23} Left {105 24} Decr_Console {105 25} Left {105 26} Left {105 27} Left {105 28} Left {105 29} Left {105 30} Left {105 31} Left {105 32} Left {105 33} Left {105 34} Left {105 35} Left {105 36} Left {105 37} Left {105 38} Left {105 39} Left {105 40} Decr_Console {105 41} Left {105 42} Left {105 43} Left {105 44} Left {105 45} Left {105 46} Left {105 47} Left {105 48} Left {105 49} Left {105 50} Left {105 51} Left {105 52} Left {105 53} Left {105 54} Left {105 55} Left {105 56} Decr_Console {105 57} Left {105 58} Left {105 59} Left {105 60} Left {105 61} Left {105 62} Left {105 63} Left {105 64} Left {105 65} Left {105 66} Left {105 67} Left {105 68} Left {105 69} Left {105 70} Left {105 71} Left {105 72} Decr_Console {105 73} Left {105 74} Left {105 75} Left {105 76} Left {105 77} Left {105 78} Left {105 79} Left {105 80} Left {105 81} Left {105 82} Left {105 83} Left {105 84} Left {105 85} Left {105 86} Left {105 87} Left {105 88} Decr_Console {105 89} Left {105 90} Left {105 91} Left {105 92} Left {105 93} Left {105 94} Left {105 95} Left {105 96} Left {105 97} Left {105 98} Left {105 99} Left {105 100} Left {105 101} Left {105 102} Left {105 103} Left {105 104} Decr_Console {105 105} Left {105 106} Left {105 107} Left {105 108} Left {105 109} Left {105 110} Left {105 111} Left {105 112} Left {105 113} Left {105 114} Left {105 115} Left {105 116} Left {105 117} Left {105 118} Left {105 119} Left {105 120} Decr_Console {105 121} Left {105 122} Left {105 123} Left {105 124} Left {105 125} Left {105 126} Left {105 127} Left {106 0} Right {106 1} Right {106 2} Right {106 3} Right {106 4} Right {106 5} Right {106 6} Right {106 7} Right {106 8} Incr_Console {106 9} Right {106 10} Right {106 11} Right {106 12} Right {106 13} Right {106 14} Right {106 15} Right {106 16} Right {106 17} Right {106 18} Right {106 19} Right {106 20} Right {106 21} Right {106 22} Right {106 23} Right {106 24} Incr_Console {106 25} Right {106 26} Right {106 27} Right {106 28} Right {106 29} Right {106 30} Right {106 31} Right {106 32} Right {106 33} Right {106 34} Right {106 35} Right {106 36} Right {106 37} Right {106 38} Right {106 39} Right {106 40} Incr_Console {106 41} Right {106 42} Right {106 43} Right {106 44} Right {106 45} Right {106 46} Right {106 47} Right {106 48} Right {106 49} Right {106 50} Right {106 51} Right {106 52} Right {106 53} Right {106 54} Right {106 55} Right {106 56} Incr_Console {106 57} Right {106 58} Right {106 59} Right {106 60} Right {106 61} Right {106 62} Right {106 63} Right {106 64} Right {106 65} Right {106 66} Right {106 67} Right {106 68} Right {106 69} Right {106 70} Right {106 71} Right {106 72} Incr_Console {106 73} Right {106 74} Right {106 75} Right {106 76} Right {106 77} Right {106 78} Right {106 79} Right {106 80} Right {106 81} Right {106 82} Right {106 83} Right {106 84} Right {106 85} Right {106 86} Right {106 87} Right {106 88} Incr_Console {106 89} Right {106 90} Right {106 91} Right {106 92} Right {106 93} Right {106 94} Right {106 95} Right {106 96} Right {106 97} Right {106 98} Right {106 99} Right {106 100} Right {106 101} Right {106 102} Right {106 103} Right {106 104} Incr_Console {106 105} Right {106 106} Right {106 107} Right {106 108} Right {106 109} Right {106 110} Right {106 111} Right {106 112} Right {106 113} Right {106 114} Right {106 115} Right {106 116} Right {106 117} Right {106 118} Right {106 119} Right {106 120} Incr_Console {106 121} Right {106 122} Right {106 123} Right {106 124} Right {106 125} Right {106 126} Right {106 127} Right {107 0} Select {107 1} Select {107 2} Select {107 3} Select {107 4} Select {107 5} Select {107 6} Select {107 7} Select {107 8} Select {107 9} Select {107 10} Select {107 11} Select {107 12} Select {107 13} Select {107 14} Select {107 15} Select {107 16} Select {107 17} Select {107 18} Select {107 19} Select {107 20} Select {107 21} Select {107 22} Select {107 23} Select {107 24} Select {107 25} Select {107 26} Select {107 27} Select {107 28} Select {107 29} Select {107 30} Select {107 31} Select {107 32} Select {107 33} Select {107 34} Select {107 35} Select {107 36} Select {107 37} Select {107 38} Select {107 39} Select {107 40} Select {107 41} Select {107 42} Select {107 43} Select {107 44} Select {107 45} Select {107 46} Select {107 47} Select {107 48} Select {107 49} Select {107 50} Select {107 51} Select {107 52} Select {107 53} Select {107 54} Select {107 55} Select {107 56} Select {107 57} Select {107 58} Select {107 59} Select {107 60} Select {107 61} Select {107 62} Select {107 63} Select {107 64} Select {107 65} Select {107 66} Select {107 67} Select {107 68} Select {107 69} Select {107 70} Select {107 71} Select {107 72} Select {107 73} Select {107 74} Select {107 75} Select {107 76} Select {107 77} Select {107 78} Select {107 79} Select {107 80} Select {107 81} Select {107 82} Select {107 83} Select {107 84} Select {107 85} Select {107 86} Select {107 87} Select {107 88} Select {107 89} Select {107 90} Select {107 91} Select {107 92} Select {107 93} Select {107 94} Select {107 95} Select {107 96} Select {107 97} Select {107 98} Select {107 99} Select {107 100} Select {107 101} Select {107 102} Select {107 103} Select {107 104} Select {107 105} Select {107 106} Select {107 107} Select {107 108} Select {107 109} Select {107 110} Select {107 111} Select {107 112} Select {107 113} Select {107 114} Select {107 115} Select {107 116} Select {107 117} Select {107 118} Select {107 119} Select {107 120} Select {107 121} Select {107 122} Select {107 123} Select {107 124} Select {107 125} Select {107 126} Select {107 127} Select {108 0} Down {108 1} Down {108 2} Down {108 3} Down {108 4} Down {108 5} Down {108 6} Down {108 7} Down {108 8} Down {108 9} Down {108 10} Down {108 11} Down {108 12} Down {108 13} Down {108 14} Down {108 15} Down {108 16} Down {108 17} Down {108 18} Down {108 19} Down {108 20} Down {108 21} Down {108 22} Down {108 23} Down {108 24} Down {108 25} Down {108 26} Down {108 27} Down {108 28} Down {108 29} Down {108 30} Down {108 31} Down {108 32} Down {108 33} Down {108 34} Down {108 35} Down {108 36} Down {108 37} Down {108 38} Down {108 39} Down {108 40} Down {108 41} Down {108 42} Down {108 43} Down {108 44} Down {108 45} Down {108 46} Down {108 47} Down {108 48} Down {108 49} Down {108 50} Down {108 51} Down {108 52} Down {108 53} Down {108 54} Down {108 55} Down {108 56} Down {108 57} Down {108 58} Down {108 59} Down {108 60} Down {108 61} Down {108 62} Down {108 63} Down {108 64} Down {108 65} Down {108 66} Down {108 67} Down {108 68} Down {108 69} Down {108 70} Down {108 71} Down {108 72} Down {108 73} Down {108 74} Down {108 75} Down {108 76} Down {108 77} Down {108 78} Down {108 79} Down {108 80} Down {108 81} Down {108 82} Down {108 83} Down {108 84} Down {108 85} Down {108 86} Down {108 87} Down {108 88} Down {108 89} Down {108 90} Down {108 91} Down {108 92} Down {108 93} Down {108 94} Down {108 95} Down {108 96} Down {108 97} Down {108 98} Down {108 99} Down {108 100} Down {108 101} Down {108 102} Down {108 103} Down {108 104} Down {108 105} Down {108 106} Down {108 107} Down {108 108} Down {108 109} Down {108 110} Down {108 111} Down {108 112} Down {108 113} Down {108 114} Down {108 115} Down {108 116} Down {108 117} Down {108 118} Down {108 119} Down {108 120} Down {108 121} Down {108 122} Down {108 123} Down {108 124} Down {108 125} Down {108 126} Down {108 127} Down {109 0} Next {109 1} Scroll_Forward {109 2} Next {109 3} Next {109 4} Next {109 5} Next {109 6} Next {109 7} Next {109 8} Next {109 9} Next {109 10} Next {109 11} Next {109 12} Next {109 13} Next {109 14} Next {109 15} Next {109 16} Next {109 17} Scroll_Forward {109 18} Next {109 19} Next {109 20} Next {109 21} Next {109 22} Next {109 23} Next {109 24} Next {109 25} Next {109 26} Next {109 27} Next {109 28} Next {109 29} Next {109 30} Next {109 31} Next {109 32} Next {109 33} Scroll_Forward {109 34} Next {109 35} Next {109 36} Next {109 37} Next {109 38} Next {109 39} Next {109 40} Next {109 41} Next {109 42} Next {109 43} Next {109 44} Next {109 45} Next {109 46} Next {109 47} Next {109 48} Next {109 49} Scroll_Forward {109 50} Next {109 51} Next {109 52} Next {109 53} Next {109 54} Next {109 55} Next {109 56} Next {109 57} Next {109 58} Next {109 59} Next {109 60} Next {109 61} Next {109 62} Next {109 63} Next {109 64} Next {109 65} Scroll_Forward {109 66} Next {109 67} Next {109 68} Next {109 69} Next {109 70} Next {109 71} Next {109 72} Next {109 73} Next {109 74} Next {109 75} Next {109 76} Next {109 77} Next {109 78} Next {109 79} Next {109 80} Next {109 81} Scroll_Forward {109 82} Next {109 83} Next {109 84} Next {109 85} Next {109 86} Next {109 87} Next {109 88} Next {109 89} Next {109 90} Next {109 91} Next {109 92} Next {109 93} Next {109 94} Next {109 95} Next {109 96} Next {109 97} Scroll_Forward {109 98} Next {109 99} Next {109 100} Next {109 101} Next {109 102} Next {109 103} Next {109 104} Next {109 105} Next {109 106} Next {109 107} Next {109 108} Next {109 109} Next {109 110} Next {109 111} Next {109 112} Next {109 113} Scroll_Forward {109 114} Next {109 115} Next {109 116} Next {109 117} Next {109 118} Next {109 119} Next {109 120} Next {109 121} Next {109 122} Next {109 123} Next {109 124} Next {109 125} Next {109 126} Next {109 127} Next {110 0} Insert {110 1} Insert {110 2} Insert {110 3} Insert {110 4} Insert {110 5} Insert {110 6} Insert {110 7} Insert {110 8} Insert {110 9} Insert {110 10} Insert {110 11} Insert {110 12} Insert {110 13} Insert {110 14} Insert {110 15} Insert {110 16} Insert {110 17} Insert {110 18} Insert {110 19} Insert {110 20} Insert {110 21} Insert {110 22} Insert {110 23} Insert {110 24} Insert {110 25} Insert {110 26} Insert {110 27} Insert {110 28} Insert {110 29} Insert {110 30} Insert {110 31} Insert {110 32} Insert {110 33} Insert {110 34} Insert {110 35} Insert {110 36} Insert {110 37} Insert {110 38} Insert {110 39} Insert {110 40} Insert {110 41} Insert {110 42} Insert {110 43} Insert {110 44} Insert {110 45} Insert {110 46} Insert {110 47} Insert {110 48} Insert {110 49} Insert {110 50} Insert {110 51} Insert {110 52} Insert {110 53} Insert {110 54} Insert {110 55} Insert {110 56} Insert {110 57} Insert {110 58} Insert {110 59} Insert {110 60} Insert {110 61} Insert {110 62} Insert {110 63} Insert {110 64} Insert {110 65} Insert {110 66} Insert {110 67} Insert {110 68} Insert {110 69} Insert {110 70} Insert {110 71} Insert {110 72} Insert {110 73} Insert {110 74} Insert {110 75} Insert {110 76} Insert {110 77} Insert {110 78} Insert {110 79} Insert {110 80} Insert {110 81} Insert {110 82} Insert {110 83} Insert {110 84} Insert {110 85} Insert {110 86} Insert {110 87} Insert {110 88} Insert {110 89} Insert {110 90} Insert {110 91} Insert {110 92} Insert {110 93} Insert {110 94} Insert {110 95} Insert {110 96} Insert {110 97} Insert {110 98} Insert {110 99} Insert {110 100} Insert {110 101} Insert {110 102} Insert {110 103} Insert {110 104} Insert {110 105} Insert {110 106} Insert {110 107} Insert {110 108} Insert {110 109} Insert {110 110} Insert {110 111} Insert {110 112} Insert {110 113} Insert {110 114} Insert {110 115} Insert {110 116} Insert {110 117} Insert {110 118} Insert {110 119} Insert {110 120} Insert {110 121} Insert {110 122} Insert {110 123} Insert {110 124} Insert {110 125} Insert {110 126} Insert {110 127} Insert {111 0} Remove {111 1} Remove {111 2} Remove {111 3} Remove {111 4} Remove {111 5} Remove {111 6} Boot {111 7} Remove {111 8} Remove {111 9} Remove {111 10} Remove {111 11} Remove {111 12} Boot {111 13} Remove {111 14} Boot {111 15} Remove {111 16} Remove {111 17} Remove {111 18} Remove {111 19} Remove {111 20} Remove {111 21} Remove {111 22} Boot {111 23} Remove {111 24} Remove {111 25} Remove {111 26} Remove {111 27} Remove {111 28} Boot {111 29} Remove {111 30} Boot {111 31} Remove {111 32} Remove {111 33} Remove {111 34} Remove {111 35} Remove {111 36} Remove {111 37} Remove {111 38} Boot {111 39} Remove {111 40} Remove {111 41} Remove {111 42} Remove {111 43} Remove {111 44} Boot {111 45} Remove {111 46} Boot {111 47} Remove {111 48} Remove {111 49} Remove {111 50} Remove {111 51} Remove {111 52} Remove {111 53} Remove {111 54} Boot {111 55} Remove {111 56} Remove {111 57} Remove {111 58} Remove {111 59} Remove {111 60} Boot {111 61} Remove {111 62} Boot {111 63} Remove {111 64} Remove {111 65} Remove {111 66} Remove {111 67} Remove {111 68} Remove {111 69} Remove {111 70} Boot {111 71} Remove {111 72} Remove {111 73} Remove {111 74} Remove {111 75} Remove {111 76} Boot {111 77} Remove {111 78} Boot {111 79} Remove {111 80} Remove {111 81} Remove {111 82} Remove {111 83} Remove {111 84} Remove {111 85} Remove {111 86} Boot {111 87} Remove {111 88} Remove {111 89} Remove {111 90} Remove {111 91} Remove {111 92} Boot {111 93} Remove {111 94} Boot {111 95} Remove {111 96} Remove {111 97} Remove {111 98} Remove {111 99} Remove {111 100} Remove {111 101} Remove {111 102} Boot {111 103} Remove {111 104} Remove {111 105} Remove {111 106} Remove {111 107} Remove {111 108} Boot {111 109} Remove {111 110} Boot {111 111} Remove {111 112} Remove {111 113} Remove {111 114} Remove {111 115} Remove {111 116} Remove {111 117} Remove {111 118} Boot {111 119} Remove {111 120} Remove {111 121} Remove {111 122} Remove {111 123} Remove {111 124} Boot {111 125} Remove {111 126} Boot {111 127} Remove {112 0} Macro {112 1} Macro {112 2} Macro {112 3} Macro {112 4} Macro {112 5} Macro {112 6} Macro {113 0} F13 {113 1} F13 {113 2} F13 {113 3} F13 {113 4} F13 {113 5} F13 {113 6} F13 {114 0} F14 {114 1} F14 {114 2} F14 {114 3} F14 {114 4} F14 {114 5} F14 {114 6} F14 {115 0} Help {115 1} Help {115 2} Help {115 3} Help {115 4} Help {115 5} Help {115 6} Help {116 0} Do {116 1} Do {116 2} Do {116 3} Do {116 4} Do {116 5} Do {116 6} Do {117 0} F17 {117 1} F17 {117 2} F17 {117 3} F17 {117 4} F17 {117 5} F17 {117 6} F17 {118 0} KP_MinPlus {118 1} KP_MinPlus {118 2} KP_MinPlus {118 3} KP_MinPlus {118 4} KP_MinPlus {118 5} KP_MinPlus {118 6} KP_MinPlus {119 0} Pause {119 1} Pause {119 2} Pause {119 3} Pause {119 4} Break {119 5} Break {119 6} Break {119 7} Break {119 8} Pause {119 9} Pause {119 10} Pause {119 11} Pause {119 12} Break {119 13} Break {119 14} Break {119 15} Break {119 16} Pause {119 17} Pause {119 18} Pause {119 19} Pause {119 20} Break {119 21} Break {119 22} Break {119 23} Break {119 24} Pause {119 25} Pause {119 26} Pause {119 27} Pause {119 28} Break {119 29} Break {119 30} Break {119 31} Break {119 32} Pause {119 33} Pause {119 34} Pause {119 35} Pause {119 36} Break {119 37} Break {119 38} Break {119 39} Break {119 40} Pause {119 41} Pause {119 42} Pause {119 43} Pause {119 44} Break {119 45} Break {119 46} Break {119 47} Break {119 48} Pause {119 49} Pause {119 50} Pause {119 51} Pause {119 52} Break {119 53} Break {119 54} Break {119 55} Break {119 56} Pause {119 57} Pause {119 58} Pause {119 59} Pause {119 60} Break {119 61} Break {119 62} Break {119 63} Break {119 64} Pause {119 65} Pause {119 66} Pause {119 67} Pause {119 68} Break {119 69} Break {119 70} Break {119 71} Break {119 72} Pause {119 73} Pause {119 74} Pause {119 75} Pause {119 76} Break {119 77} Break {119 78} Break {119 79} Break {119 80} Pause {119 81} Pause {119 82} Pause {119 83} Pause {119 84} Break {119 85} Break {119 86} Break {119 87} Break {119 88} Pause {119 89} Pause {119 90} Pause {119 91} Pause {119 92} Break {119 93} Break {119 94} Break {119 95} Break {119 96} Pause {119 97} Pause {119 98} Pause {119 99} Pause {119 100} Break {119 101} Break {119 102} Break {119 103} Break {119 104} Pause {119 105} Pause {119 106} Pause {119 107} Pause {119 108} Break {119 109} Break {119 110} Break {119 111} Break {119 112} Pause {119 113} Pause {119 114} Pause {119 115} Pause {119 116} Break {119 117} Break {119 118} Break {119 119} Break {119 120} Pause {119 121} Pause {119 122} Pause {119 123} Pause {119 124} Break {119 125} Break {119 126} Break {119 127} Break {121 0} KP_Period {121 1} KP_Period {121 2} KP_Period {121 3} KP_Period {121 4} KP_Period {121 5} KP_Period {121 6} KP_Period {121 7} KP_Period {121 8} KP_Period {121 9} KP_Period {121 10} KP_Period {121 11} KP_Period {121 12} KP_Period {121 13} KP_Period {121 14} KP_Period {121 15} KP_Period {121 16} KP_Period {121 17} KP_Period {121 18} KP_Period {121 19} KP_Period {121 20} KP_Period {121 21} KP_Period {121 22} KP_Period {121 23} KP_Period {121 24} KP_Period {121 25} KP_Period {121 26} KP_Period {121 27} KP_Period {121 28} KP_Period {121 29} KP_Period {121 30} KP_Period {121 31} KP_Period {121 32} KP_Period {121 33} KP_Period {121 34} KP_Period {121 35} KP_Period {121 36} KP_Period {121 37} KP_Period {121 38} KP_Period {121 39} KP_Period {121 40} KP_Period {121 41} KP_Period {121 42} KP_Period {121 43} KP_Period {121 44} KP_Period {121 45} KP_Period {121 46} KP_Period {121 47} KP_Period {121 48} KP_Period {121 49} KP_Period {121 50} KP_Period {121 51} KP_Period {121 52} KP_Period {121 53} KP_Period {121 54} KP_Period {121 55} KP_Period {121 56} KP_Period {121 57} KP_Period {121 58} KP_Period {121 59} KP_Period {121 60} KP_Period {121 61} KP_Period {121 62} KP_Period {121 63} KP_Period {121 64} KP_Period {121 65} KP_Period {121 66} KP_Period {121 67} KP_Period {121 68} KP_Period {121 69} KP_Period {121 70} KP_Period {121 71} KP_Period {121 72} KP_Period {121 73} KP_Period {121 74} KP_Period {121 75} KP_Period {121 76} KP_Period {121 77} KP_Period {121 78} KP_Period {121 79} KP_Period {121 80} KP_Period {121 81} KP_Period {121 82} KP_Period {121 83} KP_Period {121 84} KP_Period {121 85} KP_Period {121 86} KP_Period {121 87} KP_Period {121 88} KP_Period {121 89} KP_Period {121 90} KP_Period {121 91} KP_Period {121 92} KP_Period {121 93} KP_Period {121 94} KP_Period {121 95} KP_Period {121 96} KP_Period {121 97} KP_Period {121 98} KP_Period {121 99} KP_Period {121 100} KP_Period {121 101} KP_Period {121 102} KP_Period {121 103} KP_Period {121 104} KP_Period {121 105} KP_Period {121 106} KP_Period {121 107} KP_Period {121 108} KP_Period {121 109} KP_Period {121 110} KP_Period {121 111} KP_Period {121 112} KP_Period {121 113} KP_Period {121 114} KP_Period {121 115} KP_Period {121 116} KP_Period {121 117} KP_Period {121 118} KP_Period {121 119} KP_Period {121 120} KP_Period {121 121} KP_Period {121 122} KP_Period {121 123} KP_Period {121 124} KP_Period {121 125} KP_Period {121 126} KP_Period {121 127} KP_Period {125 0} Alt {125 1} Alt {125 2} Alt {125 3} Alt {125 4} Alt {125 5} Alt {125 6} Alt {125 7} Alt {125 8} Alt {125 9} Alt {125 10} Alt {125 11} Alt {125 12} Alt {125 13} Alt {125 14} Alt {125 15} Alt {125 16} Alt {125 17} Alt {125 18} Alt {125 19} Alt {125 20} Alt {125 21} Alt {125 22} Alt {125 23} Alt {125 24} Alt {125 25} Alt {125 26} Alt {125 27} Alt {125 28} Alt {125 29} Alt {125 30} Alt {125 31} Alt {125 32} Alt {125 33} Alt {125 34} Alt {125 35} Alt {125 36} Alt {125 37} Alt {125 38} Alt {125 39} Alt {125 40} Alt {125 41} Alt {125 42} Alt {125 43} Alt {125 44} Alt {125 45} Alt {125 46} Alt {125 47} Alt {125 48} Alt {125 49} Alt {125 50} Alt {125 51} Alt {125 52} Alt {125 53} Alt {125 54} Alt {125 55} Alt {125 56} Alt {125 57} Alt {125 58} Alt {125 59} Alt {125 60} Alt {125 61} Alt {125 62} Alt {125 63} Alt {125 64} Alt {125 65} Alt {125 66} Alt {125 67} Alt {125 68} Alt {125 69} Alt {125 70} Alt {125 71} Alt {125 72} Alt {125 73} Alt {125 74} Alt {125 75} Alt {125 76} Alt {125 77} Alt {125 78} Alt {125 79} Alt {125 80} Alt {125 81} Alt {125 82} Alt {125 83} Alt {125 84} Alt {125 85} Alt {125 86} Alt {125 87} Alt {125 88} Alt {125 89} Alt {125 90} Alt {125 91} Alt {125 92} Alt {125 93} Alt {125 94} Alt {125 95} Alt {125 96} Alt {125 97} Alt {125 98} Alt {125 99} Alt {125 100} Alt {125 101} Alt {125 102} Alt {125 103} Alt {125 104} Alt {125 105} Alt {125 106} Alt {125 107} Alt {125 108} Alt {125 109} Alt {125 110} Alt {125 111} Alt {125 112} Alt {125 113} Alt {125 114} Alt {125 115} Alt {125 116} Alt {125 117} Alt {125 118} Alt {125 119} Alt {125 120} Alt {125 121} Alt {125 122} Alt {125 123} Alt {125 124} Alt {125 125} Alt {125 126} Alt {125 127} Alt {126 0} Alt {126 1} Alt {126 2} Alt {126 3} Alt {126 4} Alt {126 5} Alt {126 6} Alt {126 7} Alt {126 8} Alt {126 9} Alt {126 10} Alt {126 11} Alt {126 12} Alt {126 13} Alt {126 14} Alt {126 15} Alt {126 16} Alt {126 17} Alt {126 18} Alt {126 19} Alt {126 20} Alt {126 21} Alt {126 22} Alt {126 23} Alt {126 24} Alt {126 25} Alt {126 26} Alt {126 27} Alt {126 28} Alt {126 29} Alt {126 30} Alt {126 31} Alt {126 32} Alt {126 33} Alt {126 34} Alt {126 35} Alt {126 36} Alt {126 37} Alt {126 38} Alt {126 39} Alt {126 40} Alt {126 41} Alt {126 42} Alt {126 43} Alt {126 44} Alt {126 45} Alt {126 46} Alt {126 47} Alt {126 48} Alt {126 49} Alt {126 50} Alt {126 51} Alt {126 52} Alt {126 53} Alt {126 54} Alt {126 55} Alt {126 56} Alt {126 57} Alt {126 58} Alt {126 59} Alt {126 60} Alt {126 61} Alt {126 62} Alt {126 63} Alt {126 64} Alt {126 65} Alt {126 66} Alt {126 67} Alt {126 68} Alt {126 69} Alt {126 70} Alt {126 71} Alt {126 72} Alt {126 73} Alt {126 74} Alt {126 75} Alt {126 76} Alt {126 77} Alt {126 78} Alt {126 79} Alt {126 80} Alt {126 81} Alt {126 82} Alt {126 83} Alt {126 84} Alt {126 85} Alt {126 86} Alt {126 87} Alt {126 88} Alt {126 89} Alt {126 90} Alt {126 91} Alt {126 92} Alt {126 93} Alt {126 94} Alt {126 95} Alt {126 96} Alt {126 97} Alt {126 98} Alt {126 99} Alt {126 100} Alt {126 101} Alt {126 102} Alt {126 103} Alt {126 104} Alt {126 105} Alt {126 106} Alt {126 107} Alt {126 108} Alt {126 109} Alt {126 110} Alt {126 111} Alt {126 112} Alt {126 113} Alt {126 114} Alt {126 115} Alt {126 116} Alt {126 117} Alt {126 118} Alt {126 119} Alt {126 120} Alt {126 121} Alt {126 122} Alt {126 123} Alt {126 124} Alt {126 125} Alt {126 126} Alt {126 127} Alt} {{2 0} 1 {2 1} ! {2 2} 1 {2 3} ! {2 4} 1 {2 5} ! {2 6} 1 {2 7} ! {2 8} 1 {2 9} ! {2 10} 1 {2 11} ! {2 12} 1 {2 13} ! {2 14} 1 {2 15} ! {2 16} 1 {2 17} ! {2 18} 1 {2 19} ! {2 20} 1 {2 21} ! {2 22} 1 {2 23} ! {2 24} 1 {2 25} ! {2 26} 1 {2 27} ! {2 28} 1 {2 29} ! {2 30} 1 {2 31} ! {2 32} 1 {2 33} ! {2 34} 1 {2 35} ! {2 36} 1 {2 37} ! {2 38} 1 {2 39} ! {2 40} 1 {2 41} ! {2 42} 1 {2 43} ! {2 44} 1 {2 45} ! {2 46} 1 {2 47} ! {2 48} 1 {2 49} ! {2 50} 1 {2 51} ! {2 52} 1 {2 53} ! {2 54} 1 {2 55} ! {2 56} 1 {2 57} ! {2 58} 1 {2 59} ! {2 60} 1 {2 61} ! {2 62} 1 {2 63} ! {3 0} 2 {3 1} @ {3 2} 2 {3 3} @ {3 4} 2 {3 5} @ {3 6} 2 {3 7} @ {3 8} 2 {3 9} @ {3 10} 2 {3 11} @ {3 12} 2 {3 13} @ {3 14} 2 {3 15} @ {3 16} 2 {3 17} @ {3 18} 2 {3 19} @ {3 20} 2 {3 21} @ {3 22} 2 {3 23} @ {3 24} 2 {3 25} @ {3 26} 2 {3 27} @ {3 28} 2 {3 29} @ {3 30} 2 {3 31} @ {4 0} 3 {4 1} # {4 2} 3 {4 3} # {4 4} 3 {4 5} # {4 6} 3 {4 7} # {4 8} 3 {4 9} # {4 10} 3 {4 11} # {4 12} 3 {4 13} # {4 14} 3 {4 15} # {4 16} 3 {4 17} # {4 18} 3 {4 19} # {4 20} 3 {4 21} # {4 22} 3 {4 23} # {4 24} 3 {4 25} # {4 26} 3 {4 27} # {4 28} 3 {4 29} # {4 30} 3 {4 31} # {4 32} 3 {4 33} # {4 34} 3 {4 35} # {4 36} 3 {4 37} # {4 38} 3 {4 39} # {4 40} 3 {4 41} # {4 42} 3 {4 43} # {4 44} 3 {4 45} # {4 46} 3 {4 47} # {4 48} 3 {4 49} # {4 50} 3 {4 51} # {4 52} 3 {4 53} # {4 54} 3 {4 55} # {4 56} 3 {4 57} # {4 58} 3 {4 59} # {4 60} 3 {4 61} # {4 62} 3 {4 63} # {5 0} 4 {5 1} {$} {5 2} 4 {5 3} {$} {5 4} 4 {5 5} {$} {5 6} 4 {5 7} {$} {5 8} 4 {5 9} {$} {5 10} 4 {5 11} {$} {5 12} 4 {5 13} {$} {5 14} 4 {5 15} {$} {5 16} 4 {5 17} {$} {5 18} 4 {5 19} {$} {5 20} 4 {5 21} {$} {5 22} 4 {5 23} {$} {5 24} 4 {5 25} {$} {5 26} 4 {5 27} {$} {5 28} 4 {5 29} {$} {5 30} 4 {5 31} {$} {5 32} 4 {5 33} {$} {5 34} 4 {5 35} {$} {5 36} 4 {5 37} {$} {5 38} 4 {5 39} {$} {5 40} 4 {5 41} {$} {5 42} 4 {5 43} {$} {5 44} 4 {5 45} {$} {5 46} 4 {5 47} {$} {5 48} 4 {5 49} {$} {5 50} 4 {5 51} {$} {5 52} 4 {5 53} {$} {5 54} 4 {5 55} {$} {5 56} 4 {5 57} {$} {5 58} 4 {5 59} {$} {5 60} 4 {5 61} {$} {5 62} 4 {5 63} {$} {6 0} 5 {6 1} % {6 2} 5 {6 3} % {6 4} 5 {6 5} % {6 6} 5 {6 7} % {6 8} 5 {6 9} % {6 10} 5 {6 11} % {6 12} 5 {6 13} % {6 14} 5 {6 15} % {6 16} 5 {6 17} % {6 18} 5 {6 19} % {6 20} 5 {6 21} % {6 22} 5 {6 23} % {6 24} 5 {6 25} % {6 26} 5 {6 27} % {6 28} 5 {6 29} % {6 30} 5 {6 31} % {6 32} 5 {6 33} % {6 34} 5 {6 35} % {6 36} 5 {6 37} % {6 38} 5 {6 39} % {6 40} 5 {6 41} % {6 42} 5 {6 43} % {6 44} 5 {6 45} % {6 46} 5 {6 47} % {6 48} 5 {6 49} % {6 50} 5 {6 51} % {6 52} 5 {6 53} % {6 54} 5 {6 55} % {6 56} 5 {6 57} % {6 58} 5 {6 59} % {6 60} 5 {6 61} % {6 62} 5 {6 63} % {7 0} 6 {7 1} ^ {7 2} 6 {7 3} ^ {7 4} 6 {7 5} ^ {7 6} 6 {7 7} ^ {7 8} 6 {7 9} ^ {7 10} 6 {7 11} ^ {7 12} 6 {7 13} ^ {7 14} 6 {7 15} ^ {7 16} 6 {7 17} ^ {7 18} 6 {7 19} ^ {7 20} 6 {7 21} ^ {7 22} 6 {7 23} ^ {7 24} 6 {7 25} ^ {7 26} 6 {7 27} ^ {7 28} 6 {7 29} ^ {7 30} 6 {7 31} ^ {8 0} 7 {8 1} & {8 2} 7 {8 3} & {8 4} 7 {8 5} & {8 6} 7 {8 7} & {8 8} 7 {8 9} & {8 10} 7 {8 11} & {8 12} 7 {8 13} & {8 14} 7 {8 15} & {8 16} 7 {8 17} & {8 18} 7 {8 19} & {8 20} 7 {8 21} & {8 22} 7 {8 23} & {8 24} 7 {8 25} & {8 26} 7 {8 27} & {8 28} 7 {8 29} & {8 30} 7 {8 31} & {8 32} 7 {8 33} & {8 34} 7 {8 35} & {8 36} 7 {8 37} & {8 38} 7 {8 39} & {8 40} 7 {8 41} & {8 42} 7 {8 43} & {8 44} 7 {8 45} & {8 46} 7 {8 47} & {8 48} 7 {8 49} & {8 50} 7 {8 51} & {8 52} 7 {8 53} & {8 54} 7 {8 55} & {8 56} 7 {8 57} & {8 58} 7 {8 59} & {8 60} 7 {8 61} & {8 62} 7 {8 63} & {9 0} 8 {9 1} * {9 2} 8 {9 3} * {9 4} 8 {9 5} * {9 6} 8 {9 7} * {9 8} 8 {9 9} * {9 10} 8 {9 11} * {9 12} 8 {9 13} * {9 14} 8 {9 15} * {9 16} 8 {9 17} * {9 18} 8 {9 19} * {9 20} 8 {9 21} * {9 22} 8 {9 23} * {9 24} 8 {9 25} * {9 26} 8 {9 27} * {9 28} 8 {9 29} * {9 30} 8 {9 31} * {9 32} 8 {9 33} * {9 34} 8 {9 35} * {9 36} 8 {9 37} * {9 38} 8 {9 39} * {9 40} 8 {9 41} * {9 42} 8 {9 43} * {9 44} 8 {9 45} * {9 46} 8 {9 47} * {9 48} 8 {9 49} * {9 50} 8 {9 51} * {9 52} 8 {9 53} * {9 54} 8 {9 55} * {9 56} 8 {9 57} * {9 58} 8 {9 59} * {9 60} 8 {9 61} * {9 62} 8 {9 63} * {10 0} 9 {10 1} ( {10 2} 9 {10 3} ( {10 4} 9 {10 5} ( {10 6} 9 {10 7} ( {10 8} 9 {10 9} ( {10 10} 9 {10 11} ( {10 12} 9 {10 13} ( {10 14} 9 {10 15} ( {10 16} 9 {10 17} ( {10 18} 9 {10 19} ( {10 20} 9 {10 21} ( {10 22} 9 {10 23} ( {10 24} 9 {10 25} ( {10 26} 9 {10 27} ( {10 28} 9 {10 29} ( {10 30} 9 {10 31} ( {10 32} 9 {10 33} ( {10 34} 9 {10 35} ( {10 36} 9 {10 37} ( {10 38} 9 {10 39} ( {10 40} 9 {10 41} ( {10 42} 9 {10 43} ( {10 44} 9 {10 45} ( {10 46} 9 {10 47} ( {10 48} 9 {10 49} ( {10 50} 9 {10 51} ( {10 52} 9 {10 53} ( {10 54} 9 {10 55} ( {10 56} 9 {10 57} ( {10 58} 9 {10 59} ( {10 60} 9 {10 61} ( {10 62} 9 {10 63} ( {11 0} 0 {11 1} ) {11 2} 0 {11 3} ) {11 4} 0 {11 5} ) {11 6} 0 {11 7} ) {11 8} 0 {11 9} ) {11 10} 0 {11 11} ) {11 12} 0 {11 13} ) {11 14} 0 {11 15} ) {11 16} 0 {11 17} ) {11 18} 0 {11 19} ) {11 20} 0 {11 21} ) {11 22} 0 {11 23} ) {11 24} 0 {11 25} ) {11 26} 0 {11 27} ) {11 28} 0 {11 29} ) {11 30} 0 {11 31} ) {11 32} 0 {11 33} ) {11 34} 0 {11 35} ) {11 36} 0 {11 37} ) {11 38} 0 {11 39} ) {11 40} 0 {11 41} ) {11 42} 0 {11 43} ) {11 44} 0 {11 45} ) {11 46} 0 {11 47} ) {11 48} 0 {11 49} ) {11 50} 0 {11 51} ) {11 52} 0 {11 53} ) {11 54} 0 {11 55} ) {11 56} 0 {11 57} ) {11 58} 0 {11 59} ) {11 60} 0 {11 61} ) {11 62} 0 {11 63} ) {12 0} - {12 1} _ {12 2} - {12 3} _ {12 4} - {12 5} _ {12 6} - {12 7} _ {12 8} - {12 9} _ {12 10} - {12 11} _ {12 12} - {12 13} _ {12 14} - {12 15} _ {12 16} - {12 17} _ {12 18} - {12 19} _ {12 20} - {12 21} _ {12 22} - {12 23} _ {12 24} - {12 25} _ {12 26} - {12 27} _ {12 28} - {12 29} _ {12 30} - {12 31} _ {13 0} = {13 1} + {13 2} = {13 3} + {13 4} = {13 5} + {13 6} = {13 7} + {13 8} = {13 9} + {13 10} = {13 11} + {13 12} = {13 13} + {13 14} = {13 15} + {13 16} = {13 17} + {13 18} = {13 19} + {13 20} = {13 21} + {13 22} = {13 23} + {13 24} = {13 25} + {13 26} = {13 27} + {13 28} = {13 29} + {13 30} = {13 31} + {13 32} = {13 33} + {13 34} = {13 35} + {13 36} = {13 37} + {13 38} = {13 39} + {13 40} = {13 41} + {13 42} = {13 43} + {13 44} = {13 45} + {13 46} = {13 47} + {13 48} = {13 49} + {13 50} = {13 51} + {13 52} = {13 53} + {13 54} = {13 55} + {13 56} = {13 57} + {13 58} = {13 59} + {13 60} = {13 61} + {13 62} = {13 63} + {16 0} q {16 1} Q {16 2} q {16 3} Q {16 4} q {16 5} Q {16 6} q {16 7} Q {16 8} q {16 9} Q {16 10} q {16 11} Q {16 12} q {16 13} Q {16 14} q {16 15} Q {16 16} Q {16 17} q {16 18} Q {16 19} q {16 20} Q {16 21} q {16 22} Q {16 23} q {16 24} Q {16 25} q {16 26} Q {16 27} q {16 28} Q {16 29} q {16 30} Q {16 31} q {17 0} w {17 1} W {17 2} w {17 3} W {17 4} w {17 5} W {17 6} w {17 7} W {17 8} w {17 9} W {17 10} w {17 11} W {17 12} w {17 13} W {17 14} w {17 15} W {17 16} W {17 17} w {17 18} W {17 19} w {17 20} W {17 21} w {17 22} W {17 23} w {17 24} W {17 25} w {17 26} W {17 27} w {17 28} W {17 29} w {17 30} W {17 31} w {18 0} e {18 1} E {18 2} e {18 3} E {18 4} e {18 5} E {18 6} e {18 7} E {18 8} e {18 9} E {18 10} e {18 11} E {18 12} e {18 13} E {18 14} e {18 15} E {18 16} E {18 17} e {18 18} E {18 19} e {18 20} E {18 21} e {18 22} E {18 23} e {18 24} E {18 25} e {18 26} E {18 27} e {18 28} E {18 29} e {18 30} E {18 31} e {19 0} r {19 1} R {19 2} r {19 3} R {19 4} r {19 5} R {19 6} r {19 7} R {19 8} r {19 9} R {19 10} r {19 11} R {19 12} r {19 13} R {19 14} r {19 15} R {19 16} R {19 17} r {19 18} R {19 19} r {19 20} R {19 21} r {19 22} R {19 23} r {19 24} R {19 25} r {19 26} R {19 27} r {19 28} R {19 29} r {19 30} R {19 31} r {20 0} t {20 1} T {20 2} t {20 3} T {20 4} t {20 5} T {20 6} t {20 7} T {20 8} t {20 9} T {20 10} t {20 11} T {20 12} t {20 13} T {20 14} t {20 15} T {20 16} T {20 17} t {20 18} T {20 19} t {20 20} T {20 21} t {20 22} T {20 23} t {20 24} T {20 25} t {20 26} T {20 27} t {20 28} T {20 29} t {20 30} T {20 31} t {21 0} y {21 1} Y {21 2} y {21 3} Y {21 4} y {21 5} Y {21 6} y {21 7} Y {21 8} y {21 9} Y {21 10} y {21 11} Y {21 12} y {21 13} Y {21 14} y {21 15} Y {21 16} Y {21 17} y {21 18} Y {21 19} y {21 20} Y {21 21} y {21 22} Y {21 23} y {21 24} Y {21 25} y {21 26} Y {21 27} y {21 28} Y {21 29} y {21 30} Y {21 31} y {22 0} u {22 1} U {22 2} u {22 3} U {22 4} u {22 5} U {22 6} u {22 7} U {22 8} u {22 9} U {22 10} u {22 11} U {22 12} u {22 13} U {22 14} u {22 15} U {22 16} U {22 17} u {22 18} U {22 19} u {22 20} U {22 21} u {22 22} U {22 23} u {22 24} U {22 25} u {22 26} U {22 27} u {22 28} U {22 29} u {22 30} U {22 31} u {23 0} i {23 1} I {23 2} i {23 3} I {23 4} i {23 5} I {23 6} i {23 7} I {23 8} i {23 9} I {23 10} i {23 11} I {23 12} i {23 13} I {23 14} i {23 15} I {23 16} I {23 17} i {23 18} I {23 19} i {23 20} I {23 21} i {23 22} I {23 23} i {23 24} I {23 25} i {23 26} I {23 27} i {23 28} I {23 29} i {23 30} I {23 31} i {24 0} o {24 1} O {24 2} o {24 3} O {24 4} o {24 5} O {24 6} o {24 7} O {24 8} o {24 9} O {24 10} o {24 11} O {24 12} o {24 13} O {24 14} o {24 15} O {24 16} O {24 17} o {24 18} O {24 19} o {24 20} O {24 21} o {24 22} O {24 23} o {24 24} O {24 25} o {24 26} O {24 27} o {24 28} O {24 29} o {24 30} O {24 31} o {25 0} p {25 1} P {25 2} p {25 3} P {25 4} p {25 5} P {25 6} p {25 7} P {25 8} p {25 9} P {25 10} p {25 11} P {25 12} p {25 13} P {25 14} p {25 15} P {25 16} P {25 17} p {25 18} P {25 19} p {25 20} P {25 21} p {25 22} P {25 23} p {25 24} P {25 25} p {25 26} P {25 27} p {25 28} P {25 29} p {25 30} P {25 31} p {26 0} {[} {26 1} \{ {26 2} {[} {26 3} \{ {26 4} {[} {26 5} \{ {26 6} {[} {26 7} \{ {26 8} {[} {26 9} \{ {26 10} {[} {26 11} \{ {26 12} {[} {26 13} \{ {26 14} {[} {26 15} \{ {26 16} {[} {26 17} \{ {26 18} {[} {26 19} \{ {26 20} {[} {26 21} \{ {26 22} {[} {26 23} \{ {26 24} {[} {26 25} \{ {26 26} {[} {26 27} \{ {26 28} {[} {26 29} \{ {26 30} {[} {26 31} \{ {27 0} \] {27 1} \} {27 2} \] {27 3} \} {27 4} \] {27 5} \} {27 6} \] {27 7} \} {27 8} \] {27 9} \} {27 10} \] {27 11} \} {27 12} \] {27 13} \} {27 14} \] {27 15} \} {27 16} \] {27 17} \} {27 18} \] {27 19} \} {27 20} \] {27 21} \} {27 22} \] {27 23} \} {27 24} \] {27 25} \} {27 26} \] {27 27} \} {27 28} \] {27 29} \} {27 30} \] {27 31} \} {30 0} a {30 1} A {30 2} a {30 3} A {30 4} a {30 5} A {30 6} a {30 7} A {30 8} a {30 9} A {30 10} a {30 11} A {30 12} a {30 13} A {30 14} a {30 15} A {30 16} A {30 17} a {30 18} A {30 19} a {30 20} A {30 21} a {30 22} A {30 23} a {30 24} A {30 25} a {30 26} A {30 27} a {30 28} A {30 29} a {30 30} A {30 31} a {31 0} s {31 1} S {31 2} s {31 3} S {31 4} s {31 5} S {31 6} s {31 7} S {31 8} s {31 9} S {31 10} s {31 11} S {31 12} s {31 13} S {31 14} s {31 15} S {31 16} S {31 17} s {31 18} S {31 19} s {31 20} S {31 21} s {31 22} S {31 23} s {31 24} S {31 25} s {31 26} S {31 27} s {31 28} S {31 29} s {31 30} S {31 31} s {32 0} d {32 1} D {32 2} d {32 3} D {32 4} d {32 5} D {32 6} d {32 7} D {32 8} d {32 9} D {32 10} d {32 11} D {32 12} d {32 13} D {32 14} d {32 15} D {32 16} D {32 17} d {32 18} D {32 19} d {32 20} D {32 21} d {32 22} D {32 23} d {32 24} D {32 25} d {32 26} D {32 27} d {32 28} D {32 29} d {32 30} D {32 31} d {33 0} f {33 1} F {33 2} f {33 3} F {33 4} f {33 5} F {33 6} f {33 7} F {33 8} f {33 9} F {33 10} f {33 11} F {33 12} f {33 13} F {33 14} f {33 15} F {33 16} F {33 17} f {33 18} F {33 19} f {33 20} F {33 21} f {33 22} F {33 23} f {33 24} F {33 25} f {33 26} F {33 27} f {33 28} F {33 29} f {33 30} F {33 31} f {34 0} g {34 1} G {34 2} g {34 3} G {34 4} g {34 5} G {34 6} g {34 7} G {34 8} g {34 9} G {34 10} g {34 11} G {34 12} g {34 13} G {34 14} g {34 15} G {34 16} G {34 17} g {34 18} G {34 19} g {34 20} G {34 21} g {34 22} G {34 23} g {34 24} G {34 25} g {34 26} G {34 27} g {34 28} G {34 29} g {34 30} G {34 31} g {35 0} h {35 1} H {35 2} h {35 3} H {35 4} h {35 5} H {35 6} h {35 7} H {35 8} h {35 9} H {35 10} h {35 11} H {35 12} h {35 13} H {35 14} h {35 15} H {35 16} H {35 17} h {35 18} H {35 19} h {35 20} H {35 21} h {35 22} H {35 23} h {35 24} H {35 25} h {35 26} H {35 27} h {35 28} H {35 29} h {35 30} H {35 31} h {36 0} j {36 1} J {36 2} j {36 3} J {36 4} j {36 5} J {36 6} j {36 7} J {36 8} j {36 9} J {36 10} j {36 11} J {36 12} j {36 13} J {36 14} j {36 15} J {36 16} J {36 17} j {36 18} J {36 19} j {36 20} J {36 21} j {36 22} J {36 23} j {36 24} J {36 25} j {36 26} J {36 27} j {36 28} J {36 29} j {36 30} J {36 31} j {37 0} k {37 1} K {37 2} k {37 3} K {37 4} k {37 5} K {37 6} k {37 7} K {37 8} k {37 9} K {37 10} k {37 11} K {37 12} k {37 13} K {37 14} k {37 15} K {37 16} K {37 17} k {37 18} K {37 19} k {37 20} K {37 21} k {37 22} K {37 23} k {37 24} K {37 25} k {37 26} K {37 27} k {37 28} K {37 29} k {37 30} K {37 31} k {38 0} l {38 1} L {38 2} l {38 3} L {38 4} l {38 5} L {38 6} l {38 7} L {38 8} l {38 9} L {38 10} l {38 11} L {38 12} l {38 13} L {38 14} l {38 15} L {38 16} L {38 17} l {38 18} L {38 19} l {38 20} L {38 21} l {38 22} L {38 23} l {38 24} L {38 25} l {38 26} L {38 27} l {38 28} L {38 29} l {38 30} L {38 31} l {39 0} {;} {39 1} : {39 2} {;} {39 3} : {39 4} {;} {39 5} : {39 6} {;} {39 7} : {39 8} {;} {39 9} : {39 10} {;} {39 11} : {39 12} {;} {39 13} : {39 14} {;} {39 15} : {39 16} {;} {39 17} : {39 18} {;} {39 19} : {39 20} {;} {39 21} : {39 22} {;} {39 23} : {39 24} {;} {39 25} : {39 26} {;} {39 27} : {39 28} {;} {39 29} : {39 30} {;} {39 31} : {39 32} {;} {39 33} : {39 34} {;} {39 35} : {39 36} {;} {39 37} : {39 38} {;} {39 39} : {39 40} {;} {39 41} : {39 42} {;} {39 43} : {39 44} {;} {39 45} : {39 46} {;} {39 47} : {39 48} {;} {39 49} : {39 50} {;} {39 51} : {39 52} {;} {39 53} : {39 54} {;} {39 55} : {39 56} {;} {39 57} : {39 58} {;} {39 59} : {39 60} {;} {39 61} : {39 62} {;} {39 63} : {40 0} ' {40 1} {"} {40 2} ' {40 3} {"} {40 4} ' {40 5} {"} {40 6} ' {40 7} {"} {40 8} ' {40 9} {"} {40 10} ' {40 11} {"} {40 12} ' {40 13} {"} {40 14} ' {40 15} {"} {40 16} ' {40 17} {"} {40 18} ' {40 19} {"} {40 20} ' {40 21} {"} {40 22} ' {40 23} {"} {40 24} ' {40 25} {"} {40 26} ' {40 27} {"} {40 28} ' {40 29} {"} {40 30} ' {40 31} {"} {40 32} ' {40 33} {"} {40 34} ' {40 35} {"} {40 36} ' {40 37} {"} {40 38} ' {40 39} {"} {40 40} ' {40 41} {"} {40 42} ' {40 43} {"} {40 44} ' {40 45} {"} {40 46} ' {40 47} {"} {40 48} ' {40 49} {"} {40 50} ' {40 51} {"} {40 52} ' {40 53} {"} {40 54} ' {40 55} {"} {40 56} ' {40 57} {"} {40 58} ' {40 59} {"} {40 60} ' {40 61} {"} {40 62} ' {40 63} {"} {41 0} ` {41 1} ~ {41 2} ` {41 3} ~ {41 4} ` {41 5} ~ {41 6} ` {41 7} ~ {41 8} ` {41 9} ~ {41 10} ` {41 11} ~ {41 12} ` {41 13} ~ {41 14} ` {41 15} ~ {41 16} ` {41 17} ~ {41 18} ` {41 19} ~ {41 20} ` {41 21} ~ {41 22} ` {41 23} ~ {41 24} ` {41 25} ~ {41 26} ` {41 27} ~ {41 28} ` {41 29} ~ {41 30} ` {41 31} ~ {43 0} \\ {43 1} | {43 2} \\ {43 3} | {43 4} \\ {43 5} | {43 6} \\ {43 7} | {43 8} \\ {43 9} | {43 10} \\ {43 11} | {43 12} \\ {43 13} | {43 14} \\ {43 15} | {43 16} \\ {43 17} | {43 18} \\ {43 19} | {43 20} \\ {43 21} | {43 22} \\ {43 23} | {43 24} \\ {43 25} | {43 26} \\ {43 27} | {43 28} \\ {43 29} | {43 30} \\ {43 31} | {44 0} z {44 1} Z {44 2} z {44 3} Z {44 4} z {44 5} Z {44 6} z {44 7} Z {44 8} z {44 9} Z {44 10} z {44 11} Z {44 12} z {44 13} Z {44 14} z {44 15} Z {44 16} Z {44 17} z {44 18} Z {44 19} z {44 20} Z {44 21} z {44 22} Z {44 23} z {44 24} Z {44 25} z {44 26} Z {44 27} z {44 28} Z {44 29} z {44 30} Z {44 31} z {45 0} x {45 1} X {45 2} x {45 3} X {45 4} x {45 5} X {45 6} x {45 7} X {45 8} x {45 9} X {45 10} x {45 11} X {45 12} x {45 13} X {45 14} x {45 15} X {45 16} X {45 17} x {45 18} X {45 19} x {45 20} X {45 21} x {45 22} X {45 23} x {45 24} X {45 25} x {45 26} X {45 27} x {45 28} X {45 29} x {45 30} X {45 31} x {46 0} c {46 1} C {46 2} c {46 3} C {46 4} c {46 5} C {46 6} c {46 7} C {46 8} c {46 9} C {46 10} c {46 11} C {46 12} c {46 13} C {46 14} c {46 15} C {46 16} C {46 17} c {46 18} C {46 19} c {46 20} C {46 21} c {46 22} C {46 23} c {46 24} C {46 25} c {46 26} C {46 27} c {46 28} C {46 29} c {46 30} C {46 31} c {47 0} v {47 1} V {47 2} v {47 3} V {47 4} v {47 5} V {47 6} v {47 7} V {47 8} v {47 9} V {47 10} v {47 11} V {47 12} v {47 13} V {47 14} v {47 15} V {47 16} V {47 17} v {47 18} V {47 19} v {47 20} V {47 21} v {47 22} V {47 23} v {47 24} V {47 25} v {47 26} V {47 27} v {47 28} V {47 29} v {47 30} V {47 31} v {48 0} b {48 1} B {48 2} b {48 3} B {48 4} b {48 5} B {48 6} b {48 7} B {48 8} b {48 9} B {48 10} b {48 11} B {48 12} b {48 13} B {48 14} b {48 15} B {48 16} B {48 17} b {48 18} B {48 19} b {48 20} B {48 21} b {48 22} B {48 23} b {48 24} B {48 25} b {48 26} B {48 27} b {48 28} B {48 29} b {48 30} B {48 31} b {49 0} n {49 1} N {49 2} n {49 3} N {49 4} n {49 5} N {49 6} n {49 7} N {49 8} n {49 9} N {49 10} n {49 11} N {49 12} n {49 13} N {49 14} n {49 15} N {49 16} N {49 17} n {49 18} N {49 19} n {49 20} N {49 21} n {49 22} N {49 23} n {49 24} N {49 25} n {49 26} N {49 27} n {49 28} N {49 29} n {49 30} N {49 31} n {50 0} m {50 1} M {50 2} m {50 3} M {50 4} m {50 5} M {50 6} m {50 7} M {50 8} m {50 9} M {50 10} m {50 11} M {50 12} m {50 13} M {50 14} m {50 15} M {50 16} M {50 17} m {50 18} M {50 19} m {50 20} M {50 21} m {50 22} M {50 23} m {50 24} M {50 25} m {50 26} M {50 27} m {50 28} M {50 29} m {50 30} M {50 31} m {51 0} , {51 1} < {51 2} , {51 3} < {51 4} , {51 5} < {51 6} , {51 7} < {51 8} , {51 9} < {51 10} , {51 11} < {51 12} , {51 13} < {51 14} , {51 15} < {51 16} , {51 17} < {51 18} , {51 19} < {51 20} , {51 21} < {51 22} , {51 23} < {51 24} , {51 25} < {51 26} , {51 27} < {51 28} , {51 29} < {51 30} , {51 31} < {51 32} , {51 33} < {51 34} , {51 35} < {51 36} , {51 37} < {51 38} , {51 39} < {51 40} , {51 41} < {51 42} , {51 43} < {51 44} , {51 45} < {51 46} , {51 47} < {51 48} , {51 49} < {51 50} , {51 51} < {51 52} , {51 53} < {51 54} , {51 55} < {51 56} , {51 57} < {51 58} , {51 59} < {51 60} , {51 61} < {51 62} , {51 63} < {52 0} . {52 1} > {52 2} . {52 3} > {52 4} . {52 5} > {52 6} . {52 7} > {52 8} . {52 9} > {52 10} . {52 11} > {52 12} . {52 13} > {52 14} . {52 15} > {52 16} . {52 17} > {52 18} . {52 19} > {52 20} . {52 21} > {52 22} . {52 23} > {52 24} . {52 25} > {52 26} . {52 27} > {52 28} . {52 29} > {52 30} . {52 31} > {53 0} / {53 1} ? {53 2} / {53 3} ? {53 4} / {53 5} ? {53 6} / {53 7} ? {53 8} / {53 9} ? {53 10} / {53 11} ? {53 12} / {53 13} ? {53 14} / {53 15} ? {53 16} / {53 17} ? {53 18} / {53 19} ? {53 20} / {53 21} ? {53 22} / {53 23} ? {53 24} / {53 25} ? {53 26} / {53 27} ? {53 28} / {53 29} ? {53 30} / {53 31} ? {57 0} { } {57 1} { } {57 2} { } {57 3} { } {57 4} { } {57 5} { } {57 6} { } {57 7} { } {57 8} { } {57 9} { } {57 10} { } {57 11} { } {57 12} { } {57 13} { } {57 14} { } {57 15} { } {57 16} { } {57 17} { } {57 18} { } {57 19} { } {57 20} { } {57 21} { } {57 22} { } {57 23} { } {57 24} { } {57 25} { } {57 26} { } {57 27} { } {57 28} { } {57 29} { } {57 30} { } {57 31} { } {86 0} < {86 1} > {86 2} | {86 3} ¦ {86 4} > {86 5} < {86 6} > {86 7} | {86 8} ¦ {86 9} > {86 10} < {86 11} > {86 12} | {86 13} ¦ {86 14} > {86 15} < {86 16} > {86 17} | {86 18} ¦ {86 19} > {86 20} < {86 21} > {86 22} | {86 23} ¦ {86 24} > {86 25} < {86 26} > {86 27} | {86 28} ¦ {86 29} > {86 30} < {86 31} > {86 32} | {86 33} ¦ {86 34} > {86 35} < {86 36} > {86 37} | {86 38} ¦ {86 39} >}} keyboardFileno 181 grabber <C:cfileMJByIm> cc ::<reference.<C______>.00000000000000000006>}}
when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ (
[ m398:0 (s630:0 s631:0 s635:0 s640:0 s644:0 s650:0 s659:0 s663:0) ]
)when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*jpg\"\ \$im\]\ ||\ \[string\ match\ \"*jpeg\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$jpegLib\ loadJpeg\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ jpegLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ png\ library\ is\ /pngLib/\ \{\n\ \ \ \ fn\ pngLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*png\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$pngLib\ loadPng\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ pngLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ \ \ fn\ gifLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ upvar\ coerceToImage\ coerceToImage\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gif\ \[\$gifLib\ loadGif\ \$im\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$coerceToImage\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \[lindex\ \[dict\ get\ \$gif\ frames\]\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ WARNING:\ This\ is\ not\ an\ Image\ object\ --\ it's\ a\ Gif\n\ \ \ \ \ \ \ \ \ \ \ \ #\ object\ and\ requires\ special\ handling\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$gif\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ gifLoader\]\ is\ an\ image\ loader\n\}\n\n\nWhen\ the\ collected\ results\ for\ \{/loader/\ is\ an\ image\ loader\}\ are\ /loaders/\ \{\n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"image\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.01)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ return\ texColor\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\}\}\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ image\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ displays\ image\ /impath/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n\}\n\nWhen\ /someone/\ wishes\ /p/\ displays\ image\ /im/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ scale\ 1.0\n\}\n with environment {{this builtin-programs/draw/image.folk}}
when Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToC (
[ m402:0 (s633:0 s646:0) ]
)when Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ vec4\ background\n\ \ \ \ \ uvec4\ tagBitsVec\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\n\ \ \ \ \ \ \ \ int\ x\ =\ int(uv.x\ *\ 10)\;\ int\ y\ =\ int(uv.y\ *\ 10)\;\n\ \ \ \ \ \ \ \ int\ bitIdx\ =\ y\ *\ 10\ +\ x\;\n\ \ \ \ \ \ \ \ uint\ bit\ =\ (tagBitsVec\[bitIdx\ /\ 32\]\ >>\ (bitIdx\ %\ 32))\ &\ 0x1\;\n\ \ \ \ \ \ \ \ return\ bit\ ==\ 1\ ?\ background\ :\ vec4(0,\ 0,\ 0,\ 1)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /writableTexture/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ AprilTag\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n with environment {{this builtin-programs/draw/apriltags.folk}}
when /wisher/ wishes /p/ runs Unix command /command/ {
Say $wisher wishes $p runs Unix command $comm ()when /wisher/ wishes /p/ runs Unix command /command/ {
Say $wisher wishes $p runs Unix command $command with arguments [list]
} with environment {{this builtin-programs/unix-commands.folk} {} {}}
when /wisher/ wishes /p/ draws toy shader /shaderCode/ \n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$s ()when /wisher/ wishes /p/ draws toy shader /shaderCode/ \n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n with environment {{this builtin-programs/gpu/toy-shader.folk} {} {sha1Lib <C:cfileq8Ho0l> cc ::<reference.<C______>.00000000000000000004>} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {pipelineLib <C:cfilekUErd7>} {toyEncoderLib <C:cfile2Bou9V> toyArgsSize 16 toyEncoder {(PushConstantsEncoder*) 0x79d1c4310a20} ^toyGlslc {{stage glsl} {
set glslfile [file tempfile /tmp/toyshaderXXXXXX].glsl
set glslfd [open $glslfile w]; puts $glslfd $glsl; close $glslfd
split [string map {\n ""} [exec glslc -fshader-stage=$stage -mfmt=num -o - $glslfile]] ","
} {builtin-programs/gpu/toy-shader.folk 71}} toyPushConstantsBlock {
layout(push_constant) uniform Args {
vec3 iResolution;
float iTime;
} args;
} cc ::<reference.<C______>.00000000000000000010>}}
when /wisher/ wishes the GPU compiles function /name/ /source/ {
tryCompileFn $wisher $name $sour (
[ m23444:0 (s30977:0) ]
[ m23443:0 (s30978:0) ]
[ m23446:0 (s30979:0) ]
[ m23447:0 (s30980:0) ]
[ m23448:0 (s30983:0) ]
[ m23449:0 (s30984:0) ]
[ m23455:0 (s30992:0) ]
[ m23466:0 (s31006:0) ]
)when /wisher/ wishes the GPU compiles function /name/ /source/ {
tryCompileFn $wisher $name $source
} with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuTextureLib <C:cfileHQKyt3>} {} {pipelineLib <C:cfilekUErd7>} {} {pipelineCompilerLib <library:/tmp/pipelineCompiler_n0FQo0.tcl>} {^defineVulkanHandleType {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} displays {} kLatency {} kGpu {} kRegionCount {} useGlfw 0 kQuadCount {} ^QueryAllFns! {{} {
set fns [dict create]
ForEach! /someone/ claims the GPU compiles function /name/ to /fn/ {
dict set fns $name $fn
}
return $fns
} {builtin-programs/gpu/draw.folk 547}} drawLib <C:cfile7Rjpvq> ^tryCompileFn {{wisher name source} {
try {
set fns [QueryAllFns!]
set fn [$pipelineCompilerLib fn $fns {*}$source]
# Technically a misnomer: the function is just stored, not
# compiled until it's been inlined into a shader.
Claim the GPU compiles function $name to $fn
} on 99 notFoundName {
puts "gpu fn $name: Waiting for $notFoundName"
When the GPU compiles function $notFoundName to /anything/ {
puts "Did compile $notFoundName"
tryCompileFn $wisher $name $source
}
} on error e {
puts stderr "Error: GPU compiles function $name: [errorInfo $e]"
Claim $wisher has error $e with info [errorInfo $e]
}
} {builtin-programs/gpu/draw.folk 554}} kDrawCount {} ^tryCompilePipeline {{wisher name source} {
try {
set fns [QueryAllFns!]
set pipeline [$pipelineCompilerLib pipeline $fns {*}$source]
puts "gpu: tryCompilePipeline: Compiled $name"
Claim the GPU compiles pipeline $name to $pipeline
} on 99 notFoundName {
puts "gpu pipeline $name: Waiting for $notFoundName"
When the GPU compiles function $notFoundName to /anything/ {
puts "Did compile $notFoundName"
tryCompilePipeline $wisher $name $source
}
} on error e {
puts stderr "Error: GPU compiles pipeline $name: [errorInfo $e]"
Claim $wisher has error $e with info [errorInfo $e]
}
} {builtin-programs/gpu/draw.folk 574}} gpu <library:/tmp/gpu_2l33ap.tcl> cc ::<reference.<C______>.00000000000000000004>}}
when /wisher/ wishes the GPU compiles pipeline /name/ /source/ {
tryCompilePipeline $wisher $name (
[ m23471:0 (s34181:0) ]
[ m23484:0 (s33276:0) ]
[ m23507:0 (s34116:0) ]
[ m23525:0 (s34648:0) ]
[ m23526:0 (s36838:0) ]
[ m23544:0 (s34568:0) ]
[ m23545:0 (s33464:0) ]
[ m23546:0 (s36521:0) ]
[ m23547:0 (s37586:0) ]
[ m23548:0 (s37502:0) ]
)when /wisher/ wishes the GPU compiles pipeline /name/ /source/ {
tryCompilePipeline $wisher $name $source
} with environment {{this builtin-programs/gpu/draw.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {defineVulkanHandleType {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} {} {gpuTextureLib <C:cfileHQKyt3>} {} {pipelineLib <C:cfilekUErd7>} {} {pipelineCompilerLib <library:/tmp/pipelineCompiler_n0FQo0.tcl>} {^defineVulkanHandleType {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}} displays {} kLatency {} kGpu {} kRegionCount {} useGlfw 0 kQuadCount {} ^QueryAllFns! {{} {
set fns [dict create]
ForEach! /someone/ claims the GPU compiles function /name/ to /fn/ {
dict set fns $name $fn
}
return $fns
} {builtin-programs/gpu/draw.folk 547}} drawLib <C:cfile7Rjpvq> ^tryCompileFn {{wisher name source} {
try {
set fns [QueryAllFns!]
set fn [$pipelineCompilerLib fn $fns {*}$source]
# Technically a misnomer: the function is just stored, not
# compiled until it's been inlined into a shader.
Claim the GPU compiles function $name to $fn
} on 99 notFoundName {
puts "gpu fn $name: Waiting for $notFoundName"
When the GPU compiles function $notFoundName to /anything/ {
puts "Did compile $notFoundName"
tryCompileFn $wisher $name $source
}
} on error e {
puts stderr "Error: GPU compiles function $name: [errorInfo $e]"
Claim $wisher has error $e with info [errorInfo $e]
}
} {builtin-programs/gpu/draw.folk 554}} kDrawCount {} ^tryCompilePipeline {{wisher name source} {
try {
set fns [QueryAllFns!]
set pipeline [$pipelineCompilerLib pipeline $fns {*}$source]
puts "gpu: tryCompilePipeline: Compiled $name"
Claim the GPU compiles pipeline $name to $pipeline
} on 99 notFoundName {
puts "gpu pipeline $name: Waiting for $notFoundName"
When the GPU compiles function $notFoundName to /anything/ {
puts "Did compile $notFoundName"
tryCompilePipeline $wisher $name $source
}
} on error e {
puts stderr "Error: GPU compiles pipeline $name: [errorInfo $e]"
Claim $wisher has error $e with info [errorInfo $e]
}
} {builtin-programs/gpu/draw.folk 574}} gpu <library:/tmp/gpu_2l33ap.tcl> cc ::<reference.<C______>.00000000000000000004>}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {monitor canvas} with /...options/ {
(
[ m51794:1062 () ]
[ m6790:1066 () ]
[ m6792:1066 () ]
[ m27945:1065 () ]
[ m27964:1057 () ]
[ m27967:1048 () ]
[ m28329:1066 () ]
[ m28348:1067 () ]
[ m28353:1067 () ]
[ m28369:1067 () ]
[ m28371:1067 () ]
[ m28406:1059 () ]
[ m28407:1059 () ]
[ m28488:1053 () ]
[ m28492:1064 () ]
[ m28528:1067 () ]
[ m28540:1036 () ]
[ m28541:1036 () ]
[ m28589:1067 () ]
[ m28593:1046 () ]
[ m28606:1050 () ]
[ m28609:1066 () ]
[ m28623:1053 () ]
[ m28633:1049 () ]
[ m28636:1067 () ]
[ m28648:1063 () ]
[ m28649:1067 () ]
[ m28680:1067 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {monitor canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {monitor canvas} with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {54-display canvas} with /...options/ (
[ m28298:1056 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {54-display canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {54-display canvas} with /...options/} settle 0ms} {settleMs 0 settleNs 0}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {63 canvas} with /...options/ {
(
[ m28579:1067 () ]
[ m28604:1050 () ]
[ m28677:1067 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {63 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {63 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {62 canvas} with /...options/ {
()when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {62 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {62 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {82 canvas} with /...options/ {
(
[ m47743:1061 () ]
[ m27965:1056 () ]
[ m27988:1067 () ]
[ m28053:1067 () ]
[ m28074:1066 () ]
[ m28095:1050 () ]
[ m28650:1062 () ]
[ m28668:1067 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {82 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {82 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {11 canvas} with /...options/ {
(
[ m18064:1056 () ]
[ m21231:1067 () ]
[ m24455:925 () ]
[ m27141:1067 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {11 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {11 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {54 canvas} with /...options/ {
(
[ m23374:1062 () ]
[ m26597:1066 () ]
[ m27255:1063 () ]
[ m27451:1063 () ]
[ m27617:1065 () ]
[ m27757:1063 () ]
[ m28136:1063 () ]
[ m28354:1066 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {54 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {54 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {83 canvas} with /...options/ {
(
[ m42686:1052 () ]
[ m1792:1051 () ]
[ m43520:1055 () ]
[ m24893:1057 () ]
[ m65130:1057 () ]
[ m47762:1064 () ]
)when /wisher/ wishes the GPU draws pipeline /name/ onto canvas {83 canvas} with /...options/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {83 canvas} with /...options/} settle 3ms} {settleMs 3 settleNs 3000000}}
when display /disp/ has width /displayWidth/ height /displayHeight/ {When /nobody/ claims a calibrati (
[ m23658:0 (s31347:0) ]
)when display /disp/ has width /displayWidth/ height /displayHeight/ {When /nobody/ claims a calibration from camera /cam/ to display {$disp} is /anything/ \n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n} with environment {{this builtin-programs/calibrate/load-calibration.folk} {} {}}
when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrins (
[ m23656:0 (s31344:0) ]
)when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrinsics /displayIntrinsics/ & /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n} with environment {{this builtin-programs/points-at.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrins (
[ m23649:0 (s31333:0) ]
)when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrinsics /displayIntrinsics/ & /tag/ has canvas /writableTextureId/ with /...wiOptions/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrins (
[ m23614:0 (s31282:0) ]
)when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrinsics /displayIntrinsics/ & /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrins (
[ m6531:985 (s53053:1174) ]
)when display /disp/ has width /displayWidth/ height /displayHeight/ {When display {$disp} has intrinsics /displayIntrinsics/ & the pose library is /poseLib/ & the quad library is /quadLib/ & the quad changer is /quadChange/ & 54 has resolved geometry /geom/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3}}
when display /disp/ has width /dispWidth/ height /dispHeight/ \n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ (
[ m23575:0 (s31222:0 s31224:0) ]
)when display /disp/ has width /dispWidth/ height /dispHeight/ \n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>}}
when display /display/ has width /displayWidth/ height /displayHeight/ {When the calibration matrix l (
[ m23572:0 (s31218:0) ]
)when display /display/ has width /displayWidth/ height /displayHeight/ {When the calibration matrix library is /matLib/ & the calibration model library is /modelLib/ & /someone/ wishes to draw calibration model /model/ using model-to-display homography /H_modelToDisplay/ with message /calibrationMessage/ \n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/draw-model.folk} {} {}}
when display /display/ has width /displayWidth/ height /displayHeight/ {When the AprilTag detector ma (
[ m23567:0 (s31211:0) ]
)when display /display/ has width /displayWidth/ height /displayHeight/ {When the AprilTag detector maker is /makeAprilTagDetector/ & the jpeg library is /jpegLib/ & the calibration model library is /modelLib/ & the calibration matrix library is /matLib/ & /someone/ wishes to calibrate camera {$camera} to display {$display} using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {}}
when display /proj/ has width /projWidth/ height /projHeight/ {When display {$proj} has intrinsics /p (
[ m23562:0 (s31204:0) ]
)when display /proj/ has width /projWidth/ height /projHeight/ {When display {$proj} has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when display monitor has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\ (
[ m23563:0 (s31205:0) ]
)when display monitor has intrinsics /projectorIntrinsics/ \n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {proj monitor projWidth 4096 projHeight 2160} {}}
when display monitor has intrinsics /displayIntrinsics/ {When /thing/ has a quad \n\n\ \ \ \ fn\ quad (
[ m23615:0 (s31283:0) ]
)when display monitor has intrinsics /displayIntrinsics/ {When /thing/ has a quad \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {}}
when display monitor has intrinsics /displayIntrinsics/ {When /tag/ has canvas /writableTextureId/ wi (
[ m23650:0 (s31334:0) ]
)when display monitor has intrinsics /displayIntrinsics/ {When /tag/ has canvas /writableTextureId/ with /...wiOptions/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {}}
when display monitor has intrinsics /displayIntrinsics/ {When /someone/ wishes /rect/ points /directi (
[ m23657:0 (s31346:0) ]
)when display monitor has intrinsics /displayIntrinsics/ {When /someone/ wishes /rect/ points /direction/ with length /l/ \n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n} with environment {{this builtin-programs/points-at.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {}}
when display monitor has intrinsics /displayIntrinsics/ {When the pose library is /poseLib/ & the qua (
[ m6534:945 (s53056:1174) ]
)when display monitor has intrinsics /displayIntrinsics/ {When the pose library is /poseLib/ & the quad library is /quadLib/ & the quad changer is /quadChange/ & 54 has resolved geometry /geom/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {}}
when Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p (
[ m422:0 (s674:0 s676:0 s680:0) ]
)when Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](p0,\ p1,\ p2,\ p0,\ p0,\ p0)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ return\ color\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ \{\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n\nWhen\ /someone/\ wishes\ /page/\ is\ filled\ with\ /...options/\ &\\\n\ \ \ \ \ /page/\ has\ region\ /region/\ \{\n\ \ set\ points\ \[region\ vertices\ \$region\]\n\ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ \{*\}\$options\n\}\n with environment {{this builtin-programs/draw/fill.folk}}
when Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surface (
[ m425:0 (s681:0 s685:0) ]
)when Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\n\ \ \ \ \ float\ dashlength\ float\ dashoffset\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\n\ \ \ \ \ \ \ \ //\ How\ far\ are\ we\ along\ the\ line?\ (in\ pixels)\n\ \ \ \ \ \ \ \ float\ t\ =\ dot(surfaceXy.xy\ -\ from,\ to\ -\ from)\ /\ l\ +\ dashoffset\;\n\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0\ &&\ floor(mod(t\ /\ dashlength,\ 2.0))\ ==\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ dashed\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n with environment {{this builtin-programs/draw/dashed-line.folk}}
when /loader/ is an image loader {
$collectLib ScheduleRecollect! $pattern $settleNs
(
[ m947:0 () ]
[ m967:0 () ]
[ m1001:0 () ]
)when /loader/ is an image loader {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/loader/ is an image loader} settle 0ms} {settleMs 0 settleNs 0}}
when Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ (
[ m436:0 (s700:0 s706:0) ]
)when Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n with environment {{this builtin-programs/draw/line.folk}}
when When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif (
[ m438:0 (s701:0) ]
)when When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n\}\n with environment {{this builtin-programs/draw/gif.folk}}
when /anyone/ wishes /source/ is connected to /sink/ {
Wish $source is connected to $sink from ce ()when /anyone/ wishes /source/ is connected to /sink/ {
Wish $source is connected to $sink from centroid to centroid
} with environment {{this builtin-programs/connections.folk} {} {}}
when /anyone/ wishes /source/ is connected to /sink/ /...options/ {When {$source} has region /source_ ()when /anyone/ wishes /source/ is connected to /sink/ /...options/ {When {$source} has region /source_region/ & {$sink} has region /sink_region/ {
if {$source == $sink} {return}
set p1 [dict_getdef $options from centroid]
set p2 [dict_getdef $options to centroid]
set source [region $p1 $source_region]
set sink [region $p2 $sink_region]
set direction [vec2 sub $sink $source]
set color [dict_getdef $options color grey]
set layer [dict_getdef $options layer 0]
set c [vec2 scale [vec2 add $source $sink] 0.5]
set angle [expr {atan2(-[lindex $direction 1], [lindex $direction 0]) - 3.14159/2}]
Wish to draw a stroke with points [list $source $sink] width 2 color $color layer $layer
Wish to draw a shape with sides 3 center $c radius 30 radians $angle color $color filled true layer $layer
}} with environment {{this builtin-programs/connections.folk} {} {}}
when /anyone/ wishes /source/ is dynamically connected to /sink/ {
Wish $source is dynamically co ()when /anyone/ wishes /source/ is dynamically connected to /sink/ {
Wish $source is dynamically connected to $sink from centroid to centroid
} with environment {{this builtin-programs/connections.folk} {} {}}
when /anyone/ wishes /source/ is dynamically connected to /sink/ /...options/ {When {$source} has reg ()when /anyone/ wishes /source/ is dynamically connected to /sink/ /...options/ {When {$source} has region /source_region/ & {$sink} has region /sink_region/ {
if {$source == $sink} {return}
set p1 [dict_getdef $options from centroid]
set p2 [dict_getdef $options to centroid]
set source [region $p1 $source_region]
set sink [region $p2 $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}]
set color [dict_getdef $options color white]
set layer [dict_getdef $options layer 0]
lassign [vec2 scale [vec2 add $source $sink] 0.5] cx cy
Wish to draw a stroke with points [list $source $sink] width 1 color $color layer $layer
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))}]
Wish to draw a shape with sides 3 center $c radius $s radians $angle color $color filled true layer $layer
}
}
}} with environment {{this builtin-programs/connections.folk} {} {maxsize 25 speed 75 spacing 50}}
when /anyone/ wishes /p/ draws sprite /path/ with /...options/ {
set frames [dict get $options fra ()when /anyone/ wishes /p/ draws sprite /path/ with /...options/ {
set frames [dict get $options frames]
set columns [dict get $options columns]
set fps [dict getdef $options fps 60]
fn loadImage
set im [loadImage $path]
set sheetWidth [$imageLib Image_width $im]
set sheetHeight [$imageLib Image_height $im]
set spriteWidth [/ $sheetWidth $columns]
set rows [/ $frames $columns]
set spriteHeight [/ $sheetHeight $rows]
When -atomicallyWithKey [list sprite $p $path] the clock time is /t/ {
set frameNumber [expr {round ($t * $fps) % $frames}]
set x [expr {($frameNumber % $columns) * $spriteWidth}]
set y [expr {($frameNumber % $rows) * $spriteHeight}]
set subimage [$imageLib slice $im $x $y $spriteWidth $spriteHeight]
Wish $p displays image $subimage with {*}$options
}
} with environment {{this builtin-programs/sprites.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {}}
when Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToCli (
[ m449:0 (s720:0 s723:0) ]
)when Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ center\ float\ radius\ float\ thickness\ vec4\ color\ int\ filled\}\ \{\n\ \ \ \ \ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ center\ +\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r)\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(surfaceXy.xy\ -\ center)\ -\ radius\;\n\ \ \ \ \ \ \ \ if\ (filled\ ==\ 1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ circle\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n\}\n with environment {{this builtin-programs/draw/circle.folk}}
when {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr { (
[ m455:0 (s773:0) ]
)when {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr {($color >> 8) & 0xFF}]
set r [expr {($color >> 16) & 0xFF}]
return [list [/ $r 255.0] [/ $g 255.0] [/ $b 255.0] 1.0]
}
set colors {
aliceblue F0F8FF
antiquewhite FAEBD7
aqua 00FFFF
aquamarine 7FFFD4
azure F0FFFF
beige F5F5DC
bisque FFE4C4
black 000000
blanchedalmond FFEBCD
blue 0000FF
blueviolet 8A2BE2
brown A52A2A
burlywood DEB887
cadetblue 5F9EA0
chartreuse 7FFF00
chocolate D2691E
coral FF7F50
cornflowerblue 6495ED
cornsilk FFF8DC
crimson DC143C
cyan 00FFFF
darkblue 00008B
darkcyan 008B8B
darkgoldenrod B8860B
darkgray A9A9A9
darkgreen 006400
darkgrey A9A9A9
darkkhaki BDB76B
darkmagenta 8B008B
darkolivegreen 556B2F
darkorange FF8C00
darkorchid 9932CC
darkred 8B0000
darksalmon E9967A
darkseagreen 8FBC8F
darkslateblue 483D8B
darkslategray 2F4F4F
darkslategrey 2F4F4F
darkturquoise 00CED1
darkviolet 9400D3
deeppink FF1493
deepskyblue 00BFFF
dimgray 696969
dimgrey 696969
dodgerblue 1E90FF
firebrick B22222
floralwhite FFFAF0
forestgreen 228B22
fuchsia FF00FF
gainsboro DCDCDC
ghostwhite F8F8FF
gold FFD700
goldenrod DAA520
gray 808080
green 008000
greenyellow ADFF2F
grey 808080
honeydew F0FFF0
hotpink FF69B4
indianred CD5C5C
indigo 4B0082
ivory FFFFF0
khaki F0E68C
lavender E6E6FA
lavenderblush FFF0F5
lawngreen 7CFC00
lemonchiffon FFFACD
lightblue ADD8E6
lightcoral F08080
lightcyan E0FFFF
lightgoldenrodyellow FAFAD2
lightgray D3D3D3
lightgreen 90EE90
lightgrey D3D3D3
lightpink FFB6C1
lightsalmon FFA07A
lightseagreen 20B2AA
lightskyblue 87CEFA
lightslategray 778899
lightslategrey 778899
lightsteelblue B0C4DE
lightyellow FFFFE0
lime 00FF00
limegreen 32CD32
linen FAF0E6
magenta FF00FF
maroon 800000
mediumaquamarine 66CDAA
mediumblue 0000CD
mediumorchid BA55D3
mediumpurple 9370DB
mediumseagreen 3CB371
mediumslateblue 7B68EE
mediumspringgreen 00FA9A
mediumturquoise 48D1CC
mediumvioletred C71585
midnightblue 191970
mintcream F5FFFA
mistyrose FFE4E1
moccasin FFE4B5
navajowhite FFDEAD
navy 000080
oldlace FDF5E6
olive 808000
olivedrab 6B8E23
orange FFA500
orangered FF4500
orchid DA70D6
palegoldenrod EEE8AA
palegreen 98FB98
paleturquoise AFEEEE
palevioletred DB7093
papayawhip FFEFD5
peachpuff FFDAB9
peru CD853F
pink FFC0CB
plum DDA0DD
powderblue B0E0E6
purple 800080
rebeccapurple 663399
red FF0000
rosybrown BC8F8F
royalblue 4169E1
saddlebrown 8B4513
salmon FA8072
sandybrown F4A460
seagreen 2E8B57
seashell FFF5EE
sienna A0522D
silver C0C0C0
skyblue 87CEEB
slateblue 6A5ACD
slategray 708090
slategrey 708090
snow FFFAFA
springgreen 00FF7F
steelblue 4682B4
tan D2B48C
teal 008080
thistle D8BFD8
tomato FF6347
turquoise 40E0D0
violet EE82EE
wheat F5DEB3
white FFFFFF
whitesmoke F5F5F5
yellow FFFF00
yellowgreen 9ACD32
}
set colorMap [dict create]
foreach {color hex} $colors {
dict set colorMap $color [hexcolor $hex]
}
Claim the color map is $colorMap
} with environment {{this builtin-programs/draw/color-map.folk}}
when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags - (
[ m464:0 (s748:0) ]
)when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
}
} with environment {{this builtin-programs/image/gif-lib.folk}}
when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpe (
[ m466:0 (s749:0) ]
)when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
}
} with environment {{this builtin-programs/image/jpeg-lib.folk}}
when When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ (
[ m470:0 (s754:0) ]
)when When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/draw/text.folk}}
when {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width (
[ m471:0 (s1395:0 s1397:0) ]
)when {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width;
uint32_t height;
int components;
uint32_t bytesPerRow;
// Weird: this can be mutated if you want the image to be
// reloaded into the GPU.
uint64_t uniq;
uint8_t* data;
}
# Note that this returns an image whose lifetime is tied to the original image.
$cc proc slice {Image im double x double y double subwidth double subheight} Image {
uint8_t *subdata = im.data + (int)y*im.bytesPerRow + (int)x*im.components;
return (Image) {
.width = (uint32_t)subwidth,
.height = (uint32_t)subheight,
.components = im.components,
.bytesPerRow = im.bytesPerRow,
.data = subdata,
.uniq = im.uniq
};
}
$cc proc imageNew {int width int height int components int uniq} Image {
uint8_t* data = malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data,
.uniq = uniq
};
}
$cc proc imageFree {Image image} void {
free(image.data);
}
# Note that this returns a fresh (copied) image. imVertices are
# coordinates in im, clockwise from top-left.
$cc proc warpQuad {Image im double[4][2] imVertices
int outWidth int outHeight} Image {
if (outWidth <= 0 || outHeight <= 0 ||
outWidth > (int)im.width * 4 || outHeight > (int)im.height * 4) {
FOLK_ERROR("warpQuad: bad dimensions %d x %d (source %d x %d)",
outWidth, outHeight, im.width, im.height);
}
Image out = imageNew(outWidth, outHeight, im.components, im.uniq);
// imVertices are clockwise from top-left: [TL, TR, BR, BL]
double tlX = imVertices[0][0], tlY = imVertices[0][1];
double trX = imVertices[1][0], trY = imVertices[1][1];
double brX = imVertices[2][0], brY = imVertices[2][1];
double blX = imVertices[3][0], blY = imVertices[3][1];
// For each output pixel, find corresponding source pixel using bilinear mapping
double invW = (outWidth > 1) ? 1.0 / (outWidth - 1) : 0.0;
double invH = (outHeight > 1) ? 1.0 / (outHeight - 1) : 0.0;
for (int y = 0; y < outHeight; y++) {
// Hoist v and y-dependent edge coords outside x-loop
double v = y * invH;
double leftX = tlX + v * (blX - tlX);
double leftY = tlY + v * (blY - tlY);
double rightX = trX + v * (brX - trX);
double rightY = trY + v * (brY - trY);
double stepX = (rightX - leftX) * invW;
double stepY = (rightY - leftY) * invW;
uint8_t *dstRow = out.data + y * out.bytesPerRow;
double srcX = leftX, srcY = leftY;
for (int x = 0; x < outWidth; x++, srcX += stepX, srcY += stepY) {
uint8_t *dstPixel = dstRow + x * out.components;
int ix = (int)srcX;
int iy = (int)srcY;
// Fixed-point fractions (0..255)
int fx = (int)((srcX - ix) * 256);
int fy = (int)((srcY - iy) * 256);
if (ix >= 0 && ix < (int)im.width - 1 && iy >= 0 && iy < (int)im.height - 1) {
uint8_t *p00 = im.data + iy * im.bytesPerRow + ix * im.components;
uint8_t *p10 = p00 + im.components;
uint8_t *p01 = p00 + im.bytesPerRow;
uint8_t *p11 = p01 + im.components;
for (int c = 0; c < im.components; c++) {
int top = p00[c] + ((fx * (p10[c] - p00[c])) >> 8);
int bot = p01[c] + ((fx * (p11[c] - p01[c])) >> 8);
dstPixel[c] = (uint8_t)(top + ((fy * (bot - top)) >> 8));
}
} else if (ix >= 0 && ix < (int)im.width && iy >= 0 && iy < (int)im.height) {
uint8_t *srcPixel = im.data + iy * im.bytesPerRow + ix * im.components;
for (int c = 0; c < im.components; c++) {
dstPixel[c] = srcPixel[c];
}
} else {
for (int c = 0; c < im.components; c++) {
dstPixel[c] = 0;
}
}
}
}
return out;
}
set imageLib [$cc compile]
Claim the image library is $imageLib
fn defineImageArgtype {uvx} {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
}
Claim the image uvx argtype definer is [fn defineImageArgtype]
} with environment {{this builtin-programs/image/image-lib.folk}}
when set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ (
[ m487:0 (s777:0) ]
)when set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ create\]\n\ \ \ \ foreach\ stmt\ \[Query!\ /...anything/\]\ \{\n\ \ \ \ \ \ \ \ set\ stmtRef\ \[dict\ get\ \$stmt\ __ref\]\n\ \ \ \ \ \ \ \ set\ label\ \[\$dbLib\ clause\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ label\ \[join\ \[lmap\ line\ \[split\ \$label\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ set\ label\ \[string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$label\]\]\n\ \ \ \ \ \ \ \ set\ stmtParentCount\ \[\$dbLib\ statementParentCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ stmtPtrCount\ \[\$dbLib\ statementPtrCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ \\\[label=\\\"\$stmtRef\ (\$stmtParentCount\ parents)\ (\$stmtPtrCount\ ptrs):\ \$label\\\"\\\]\;\"\n\n\ \ \ \ \ \ \ \ foreach\ childMatchRef\ \[\$dbLib\ childMatches\ \$db\ \$stmtRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ ->\ <\$childMatchRef>\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ matchRefs\ \$childMatchRef\ true\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ foreach\ \{matchRef\ _\}\ \$matchRefs\ \{\n\ \ \ \ \ \ \ \ set\ match\ \[\$dbLib\ matchAcq\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ if\ \{\$match\ eq\ \"(Match*)\ 0x0\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ set\ matchPtrCount\ \[\$dbLib\ matchPtrCount\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ set\ matchIsAlive\ \[\$dbLib\ matchIsAlive\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ \\\[label=\\\"\$matchRef\ (alive?\ \$matchIsAlive)\ (\$matchPtrCount)\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ childStatementRef\ \[\$dbLib\ childStatements\ \$db\ \$matchRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ ->\ <\$childStatementRef>\;\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$dbLib\ matchRel\ \$db\ \$match\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[join\ \$dot\ \"\\n\"\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWhen\ the\ db\ library\ is\ /dbLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/web/dep-graph.folk}}
when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc (
[ m489:0 (s778:0) ]
)when {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
}
} with environment {{this builtin-programs/image/png-lib.folk}}
when #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ fr (
[ m490:0 (s780:0 s784:0 s787:0) ]
)when #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ from\ the\ Web\ UI,\ or\ declare\ it\ using\ Folk:\n#\n#\ \ \ \ \ Assert\ \$::thisNode\ claims\ printer\ \"printer-name\"\ is\ a\ cups\ printer\ with\ url\ \"http://url/ipp/print\"\ driver\ \"everywhere\"\n#\n#\ Lastly,\ you\ need\ to\ declare\ a\ default\ printer\ and\ default\ paper\ format:\n#\ (make\ sure\ that\ the\ default\ printer\ supports\ the\ default\ paper\ format)\n#\n#\ \ \ \ \ Claim\ printer\ my-printer\ is\ the\ default\ printer\n#\ \ \ \ \ Claim\ paper\ format\ a4\ is\ the\ default\ paper\ format\n\nClaim\ the\ paper\ formats\ are\ \{\n\ \ \ \ letter\ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\ \ \ \ a4\ \ \ \ \ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{595\ 842\}\}\n\ \ \ \ indexcard\ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\}\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n\}\n\nSubscribe:\ print\ pdf\ /pdfPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n\}\n with environment {{this builtin-programs/print/print.folk}}
when {When the collected results for [list /someone/ wishes the web server handles route /route/ with (
[ m502:0 (s802:0) ]
)when {When the collected results for [list /someone/ wishes the web server handles route /route/ with /...options/] are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
}
} with environment {{this builtin-programs/web/nav.folk}}
when {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command { (
[ m517:0 (s825:0) ]
)when {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
}
} with environment {{this builtin-programs/web/block-stats.folk}}
when When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ th (
[ m524:0 (s836:0) ]
)when When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ draw\ library\ is\ /drawLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ endcflags\ -lpng\n\ \ \ \ \$cc\ cflags\ -I./vendor\n\ \ \ \ \$cc\ endcflags\ \$vmaDll\n\ \ \ \ \$cc\ include\ <png.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ \ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ \ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ to\ make\ gpuLib\ extend\ properly\n\ \ \ \ \$cc\ typedef\ \{struct\ PushConstantsEncoder\}\ PushConstantsEncoder\n\ \ \ \ \$cc\ typedef\ \{struct\ Pipeline\}\ Pipeline\n\ \ \ \ \$cc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\ \ \ \ \$cc\ argtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ \ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ rtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ char\ buf\[100\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ extend\ \$gpuLib\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ extend\ \$gpuTextureLib\n\ \ \ \ \$cc\ proc\ texturesLibInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ volkInitialize()\;\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyTextureFromGpu\ \{GpuTextureHandle\ han\}\ Image\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ getGpuTexture(han)\;\n\ \ \ \ \ \ \ \ if\ (!block->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (Image)\{0\}\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ block->width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ block->height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\ //\ HACK:\ hard-coded\ for\ now\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ block->width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ malloc(block->width\ *\ block->height\ *\ 4)\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ size_t\ stagingBufferSize\ =\ block->width\ *\ block->height\ *\ 4\;\n\ \ \ \ \ \ \ \ createBuffer(stagingBufferSize,\ VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &stagingBuffer,\ &stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n\ \ \ \ \ \ \ \ \ \ \ \ .oldLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .image\ =\ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseMipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.levelCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ image\ to\ buffer\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferOffset\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferRowLength\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferImageHeight\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.mipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageOffset\ =\ \{0,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ .imageExtent\ =\ \{block->width,\ block->height,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdCopyImageToBuffer(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ ®ion\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ image\ layout\ back\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ VkFence\ fence\ =\ getFence()\;\n\ \ \ \ \ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ staging\ buffer\ back\ to\ CPU\n\ \ \ \ \ \ \ \ void*\ data\;\n\ \ \ \ \ \ \ \ vmaMapMemory(vmaGetAllocator(),\ stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ memcpy(im.data,\ data,\ stagingBufferSize)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ //\ Cleanup\ staging\ buffer\n\ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\ stagingBuffer,\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ struct\ WriteState\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ buffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t*\ size\;\ \n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ void\ pngWriteCallback(png_structp\ png_ptr,\ png_bytep\ data,\ png_size_t\ length)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ WriteState*\ state\ =\ (struct\ WriteState*)png_get_io_ptr(png_ptr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(state->buffer\ +\ *state->size,\ data,\ length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ *state->size\ +=\ length\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ imageToPngBuffer\ \{Image\ im\ size_t*\ outSize\}\ uint8_t*\ \{\n\ \ \ \ \ \ \ \ size_t\ bufferSize\ =\ im.width\ *\ im.height\ *\ im.components\ *\ 2\;\ //\ max\ size\ estimate\n\ \ \ \ \ \ \ \ uint8_t*\ buffer\ =\ malloc(bufferSize)\;\n\ \ \ \ \ \ \ \ *outSize\ =\ 0\;\n\n\ \ \ \ \ \ \ \ png_structp\ png_w\ =\ png_create_write_struct(PNG_LIBPNG_VER_STRING,\ NULL,\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (!png_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_infop\ info_w\ =\ png_create_info_struct(png_w)\;\n\ \ \ \ \ \ \ \ if\ (!info_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ struct\ WriteState\ state\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .buffer\ =\ buffer,\n\ \ \ \ \ \ \ \ \ \ \ \ .size\ =\ outSize\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ png_set_write_fn(png_w,\ &state,\ pngWriteCallback,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGBA,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGB,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_bytep*\ row_pointers\ =\ malloc(sizeof(png_bytep)\ *\ im.height)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ row_pointers\[y\]\ =\ im.data\ +\ y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_set_rows(png_w,\ info_w,\ row_pointers)\;\n\ \ \ \ \ \ \ \ png_write_png(png_w,\ info_w,\ PNG_TRANSFORM_IDENTITY,\ NULL)\;\n\n\ \ \ \ \ \ \ \ free(row_pointers)\;\n\ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\n\ \ \ \ \ \ \ \ *outSize\ =\ bufferSize\;\n\ \ \ \ \ \ \ \ return\ buffer\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyAllTexturesFromGpu\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (getGpuTexture(i)->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Image\ im\ =\ copyTextureFromGpu(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pngSize\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ pngData\ =\ imageToPngBuffer(im,\ &pngSize)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_ObjPrintf(\"Image\ %d\ (%d\ x\ %d)\",\ i,\ im.width,\ im.height))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_NewStringObj(interp,\ (char*)pngData,\ pngSize))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(pngData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(im.data)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ set\ texturesLib\ \[\$cc\ compile\]\n\ \ \ \ \$texturesLib\ texturesLibInit\n\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/textures\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ package\ require\ base64\n\n\ \ \ \ \ \ \ \ set\ images\ \[\$texturesLib\ copyAllTexturesFromGpu\]\n\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>Textures</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ img\ \{\ max-width:\ 100%\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{description\ imageData\}\ \$images\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ b64\ \[binary\ encode\ base64\ \$imageData\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \{<div><p>%s</p><img\ src=\"data:image/png\;base64,%s\"></div>\}\ \$description\ \$b64\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/web/textures.folk}}
when Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handl (
[ m525:0 (s847:0) ]
)when Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handler\ \{\n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n\}\n with environment {{this builtin-programs/web/setup.folk}}
when {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Ex (
[ m534:0 (s849:0) ]
)when {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
}
} with environment {{this builtin-programs/web/program.folk}}
when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" w (
[ m541:0 (s852:0) ]
)when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
}
} with environment {{this builtin-programs/web/holds.folk}}
when {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
(
[ m549:0 (s60040:0) ]
)when {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
$cc include "db.h"
$cc include "common.h"
$cc include "vendor/stb_ds.h"
$cc code {
typedef struct ListOfEdgeTo {
size_t capacityEdges;
size_t nEdges; // This is an estimate.
uint64_t edges[];
} ListOfEdgeTo;
typedef struct GenRc {
int16_t rc;
int gen: 15;
bool alive: 1;
} GenRc;
#include <pthread.h>
}
set dbCFd [open "db.c" r]; set dbC [read $dbCFd]; close $dbCFd
$cc code [lindex [regexp -inline {typedef struct Destructor \{.*\} Destructor;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct DestructorSet \{.*\} DestructorSet;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Statement \{.*\} Statement;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Match \{.*\} Match;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Hold \{.*\} Hold;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct StatementRefList \{.*\} StatementRefList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersionList \{.*\} AtomicallyVersionList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersion \{.*\} AtomicallyVersion;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Atomically \{.*\} Atomically;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Db \{.*\} Db;} $dbC] 0]
$cc argtype StatementRef { StatementRef $argname; sscanf(Jim_String($obj), "s%d:%d", &$argname.idx, &$argname.gen); }
$cc argtype MatchRef { MatchRef $argname; sscanf(Jim_String($obj), "m%d:%d", &$argname.idx, &$argname.gen); }
$cc proc clauseToJimObj {Clause* clause} Jim_Obj* {
Jim_Obj* termObjs[clause->nTerms];
for (int i = 0; i < clause->nTerms; i++) {
termObjs[i] = Jim_NewStringObj(interp, termPtr(clause->terms[i]),
termLen(clause->terms[i]));
}
return Jim_NewListObj(interp, termObjs, clause->nTerms);
}
$cc proc statementParentCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
int ret = stmt->parentCount;
statementRelease(db, stmt);
return ret;
}
$cc proc statementPtrCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
GenRc genRc = stmt->genRc;
int ret = genRc.rc - 1;
statementRelease(db, stmt);
return ret;
}
$cc proc clause {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewStringObj(interp, "(null)", -1); }
Jim_Obj* ret = clauseToJimObj(statementClause(stmt));
statementRelease(db, stmt);
return ret;
}
$cc proc childMatches {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewEmptyStringObj(interp); }
pthread_mutex_lock(&stmt->childMatchesMutex);
if (stmt->childMatches == NULL) {
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[stmt->childMatches->nEdges];
for (int i = 0; i < stmt->childMatches->nEdges; i++) {
MatchRef child = { .val = stmt->childMatches->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("m%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc matchAcq {Db* db MatchRef matchRef} Match* {
return matchAcquire(db, matchRef);
}
$cc proc matchRel {Db* db Match* match} void {
matchRelease(db, match);
}
$cc proc matchPtrCount {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int ret = genRc.rc - 1;
matchRelease(db, match);
return ret;
}
$cc proc matchIsAlive {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int alive = genRc.alive;
matchRelease(db, match);
return alive;
}
$cc code {
#define CHILD_STATEMENTS_REMOVING ((ListOfEdgeTo*)1)
}
$cc proc childStatements {Db* db MatchRef matchRef} Jim_Obj* {
Match* match = matchAcquire(db, matchRef);
if (match == NULL) { return Jim_NewStringObj(interp, "", -1); }
pthread_mutex_lock(&match->childStatementsMutex);
if (match->childStatements == NULL ||
match->childStatements == CHILD_STATEMENTS_REMOVING) {
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[match->childStatements->nEdges];
for (int i = 0; i < match->childStatements->nEdges; i++) {
StatementRef child = { .val = match->childStatements->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("s%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc countAliveStatements {Db* db} int {
int count = 0;
for (int i = 1; i < 65536; i++) { // slot 0 is reserved
GenRc genRc = db->statementPool[i].genRc;
if (genRc.alive) {
count++;
}
}
return count;
}
$cc proc holds {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->holdsMutex);
for (int i = 0; i < shlen(db->holds); i++) {
Hold* hold = &db->holds[i];
Statement* stmt = statementAcquire(db, hold->statement);
if (stmt == NULL) {
fprintf(stderr, "db-lib: holds: WARNING: held statement on (%s) is invalid! (s%d:%d)\n",
hold->key, hold->statement.idx, hold->statement.gen);
continue;
}
char* clauseStr = clauseToString(statementClause(stmt));
Jim_Obj* holdObjv[] = {
Jim_NewStringObj(interp, hold->key, -1),
Jim_NewIntObj(interp, hold->version),
Jim_ObjPrintf("s%d:%d", hold->statement.idx, hold->statement.gen),
Jim_NewStringObj(interp, clauseStr, -1)
};
statementRelease(db, stmt);
free(clauseStr);
Jim_Obj* holdObj = Jim_NewListObj(interp, holdObjv,
sizeof(holdObjv)/sizeof(holdObjv[0]));
Jim_ListAppendElement(interp, retObj, holdObj);
}
mutexUnlock(&db->holdsMutex);
return retObj;
}
$cc proc atomicallys {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->atomicallysMutex);
for (int i = 0; i < sizeof(db->atomicallys)/sizeof(db->atomicallys[0]); i++) {
Atomically* atomically = &db->atomicallys[i];
if (atomically->key == NULL) { continue; }
// Count versions in allVersions list
int versionCount = 0;
AtomicallyVersionList* vl = atomically->allVersions;
while (vl != NULL) {
versionCount++;
vl = vl->next;
}
// Get latest converged version info
int latestConvergedNumber = -1;
if (atomically->latestConvergedVersion != NULL) {
latestConvergedNumber = atomically->latestConvergedVersion->number;
}
Jim_Obj* atomicallyObjv[] = {
Jim_NewStringObj(interp, atomically->key, -1),
Jim_NewIntObj(interp, latestConvergedNumber),
Jim_NewIntObj(interp, versionCount)
};
Jim_Obj* atomicallyObj = Jim_NewListObj(interp, atomicallyObjv,
sizeof(atomicallyObjv)/sizeof(atomicallyObjv[0]));
Jim_ListAppendElement(interp, retObj, atomicallyObj);
}
mutexUnlock(&db->atomicallysMutex);
return retObj;
}
return [$cc compile]
}}]
} with environment {{this builtin-programs/web/db-lib.folk}}
when set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ - (
[ m553:0 (s1164:0) ]
)when set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ -I./vendor/tracy/public\n\ \ \ \ \$cc\ include\ \"workqueue.h\"\n\ \ \ \ \$cc\ include\ \"common.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ extern\ ThreadControlBlock\ threads\[\]\;\n\ \ \ \ \ \ \ \ extern\ int\ _Atomic\ threadCount\;\n\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ int\ unsafe_workQueueCopy(WorkQueueItem*\ into,\ int\ maxn,\ WorkQueue*\ q)\;\n\ \ \ \ \ \ \ \ extern\ void\ traceItem(char*\ buf,\ size_t\ bufsz,\ WorkQueueItem\ item)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ itemToStringObj(WorkQueueItem\ item)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ char\ buf\[10000\]\;\ traceItem(buf,\ sizeof(buf),\ item)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerTids\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ //\ Fallback\ on\ macOS,\ where\ we\ don't\ have\ /proc\ to\ query\ all\n\ \ \ \ \ \ \ \ //\ threads\ of\ the\ Folk\ process.\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ threads\[i\].tid))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfo\ \{int\ threadIndex\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ if\ (threadIndex\ >=\ threadCount\ ||\ threads\[threadIndex\].tid\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ThreadControlBlock\ *thread\ =\ &threads\[threadIndex\]\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ thread->currentItem\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\ Jim_NewStringObj(interp,\ \"op\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(item))\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ items\[100\]\;\n\ \ \ \ \ \ \ \ int\ nitems\ =\ unsafe_workQueueCopy(items,\ 100,\ thread->workQueue)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ workQueueObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nitems\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ workQueueObj,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(items\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"workQueue\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ workQueueObj)\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"isDeactivated\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ thread->isDeactivated))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"currentItemStartTimestamp\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ObjPrintf(\"%\"\ PRId64,\ thread->currentItemStartTimestamp))\;\n\n\ \ \ \ \ \ \ \ int64_t\ now\ =\ timestamp_get(thread->clockid)\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"elapsed\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ (double)(now\ -\ thread->currentItemStartTimestamp)\ /\ 1000.0))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_allocs\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_allocs))\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_frees\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_frees))\;\n\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfoFromTid\ \{int\ tid\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ ==\ tid)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ workerInfo(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #include\ \"vendor/c11-queues/mpmc_queue.h\"\n\ \ \ \ \ \ \ \ extern\ struct\ mpmc_queue\ globalWorkQueue\;\n\ \ \ \ \ \ \ \ extern\ _Atomic\ int\ globalWorkQueueSize\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ globalWorkQueueAvailable\ \{\}\ size_t\ \{\n\ \ \ \ \ \ \ \ return\ mpmc_queue_available(&globalWorkQueue)\;\n\ \ \ \ \}\n\ \ \ \ #\ Unsafely\ peeks\ at\ the\ queue.\n\ \ \ \ \$cc\ proc\ globalWorkQueueItems\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj\ *ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ size_t\ head\ =\ globalWorkQueue.head\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ head\;\ i\ <\ globalWorkQueue.tail\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ mpmc_queue_cell\ *cell\ =\ &globalWorkQueue.buffer\[i\ &\ globalWorkQueue.buffer_mask\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ *ptr\ =\ cell->data\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ *ptr\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ itemToStringObj(item))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nWish\ the\ web\ server\ handles\ route\ \"/threads\"\ with\ handler\ \{\n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n with environment {{this builtin-programs/web/threads.folk}}
when try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ s (
[ m563:0 (s1406:0 s49248:1243 s49257:1252 s49280:1252 s49284:1252 s49296:1252 s49301:1252 s49308:1252) ]
)when try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ so\ closing\ a\ tab\ doesn't\ crash\ Folk,\ but\n#\ we\ don't\ want\ to\ block/ignore,\ because\ that\ will\ cause\ child\n#\ processes\ to\ also\ block/ignore\ and\ behave\ weirdly.\nsignal\ handle\ SIGPIPE\n\n#\ To\ force\ a\ rebuild:\ rm\ vendor/wslay/Makefile\nif\ \{!\[file\ exists\ vendor/wslay/Makefile\]\}\ \{\n\ \ \ \ puts\ \"web:\ Configuring\ libwslay...\"\n\ \ \ \ exec\ sh\ -c\ \{cd\ vendor/wslay\ &&\ autoreconf\ -i\ &&\ automake\ &&\ autoconf\ &&\ ./configure\}\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"web:\ Building\ libwslay...\"\nexec\ make\ -C\ vendor/wslay\ >@stdout\ 2>@stderr\nputs\ \"web:\ libwslay\ built.\"\n\nsource\ \"lib/ws.tcl\"\n#\ We\ export\ wsLib\ so\ that\ other\ threads\ can\ emit\ messages\ onto\n#\ websockets.\nClaim\ the\ websocket\ library\ is\ \$wsLib\n\nproc\ handleConnect\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ timeout\ 2000\n\ \ \ \ fileevent\ \$chan\ readable\ \[list\ apply\ \{\{chan\ addr\}\ \{\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleRead\ \$chan\ \$addr\n\ \ \ \ \ \ \ \ \}\ on\ signal\ \{sig\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$sig\ on\ \$chan\ \$addr\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$chan\ \$addr\]\n\}\n\nproc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\nproc\ readFile\ \{filename\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\;\ close\ \$fd\;\ return\ \$response\n\}\n\nproc\ headerGet\ \{headers\ name\ args\}\ \{\n\ \ \ \ foreach\ \{k\ v\}\ \$headers\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ -nocase\ \$k\ \$name\]\}\ \{\ return\ \$v\ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[llength\ \$args\]\ >\ 0\}\ \{\ return\ \[lindex\ \$args\ 0\]\ \}\n\ \ \ \ error\ \"missing\ HTTP\ header\ \$name\"\n\}\n\nproc\ handlePage\ \{path\ httpStatusVar\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ switch\ -exact\ --\ \$path\ \{\n\ \ \ \ \ \ \ \ \"/favicon.ico\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"image/x-icon\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/favicon.ico\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/style.css\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/css\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/style.css\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/lib/folk.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"lib/folk.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/vendor/idiomorph.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"vendor/idiomorph.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ \$httpStatusVar\ httpStatus\n\ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 404\ Not\ Found\"\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <b>\$path</b>\ Not\ found.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ parseQueryString\ \{queryString\}\ \{\n\ \ \ \ set\ QUERY\ \[dict\ create\]\n\ \ \ \ if\ \{\$queryString\ eq\ \"\"\}\ \{\ return\ \$QUERY\ \}\n\n\ \ \ \ set\ queryString\ \[string\ range\ \$queryString\ 1\ end\]\n\ \ \ \ foreach\ pair\ \[split\ \$queryString\ &\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^=\]*)=(.*)\$\}\ \$pair\ ->\ key\ value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ URL\ decode\ key\ and\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$key\ \{\ \}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$key\ \{\[format\ %c\ 0x\\1\]\}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[subst\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$value\ \{\ \}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$value\ \{\[format\ %c\ 0x\\1\]\}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[subst\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ QUERY\ \$key\ \$value\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$QUERY\n\}\n\nfn\ HtmlWhen\ args\ \{\n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n\}\n\nproc\ handleRead\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ buffering\ none\n\n\ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ set\ firstline\ \$line\n\n\ \ \ \ #\ puts\ \"Http\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%H:%M:%S\"\]):\ \$chan\ \$addr:\ \$line\"\n\ \ \ \ set\ headers\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ \ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{\ break\ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ Http:\ (\$line)\"\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^\\s:\]+)\\s*:\\s*(.+)\}\ \$line\ ->\ k\ v\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ headers\ \$k\ \$v\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ stderr\ \"Http:\ Weird\ line:\ \$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[regexp\ \{GET\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\ &&\ \$path\ ne\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ set\ response\ \{\}\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ForEach!\ /someone/\ wishes\ the\ web\ server\ handles\ route\ /route/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ handler\ \[dict\ get\ \$options\ handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[regexp\ -inline\ ^\$\{route\}(\\\\?.*)?\$\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$vars\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ queryString\ \[lindex\ \$vars\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ QUERY\ \[parseQueryString\ \$queryString\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^html\ \[proc\ html\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ text/html\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^json\ \[proc\ json\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ application/json\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$handler\ 0\]\ eq\ \"applyBlock\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ create\ QUERY\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$vars\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ \$i\ \[lindex\ \$vars\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ handler\ 2\ \[linsert\ \[lindex\ \$handler\ 2\]\ end\ \$env\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[\{*\}\$handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varNames\ \[lseq\ \[llength\ \$vars\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ varNames\ QUERY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[apply\ \[list\ \$varNames\ \$handler\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$vars\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$response\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[handlePage\ \$path\ httpStatus\ contentType\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"\$httpStatus\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$response\ statusAndHeaders\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Response\ not\ generated\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ \{err\ opts\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errorInfo\ \[dict\ get\ \$opts\ -errorinfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ src\ \[lindex\ \$errorInfo\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Web\ error\ in\ \$src\ (\$path):\ \$err\\n\ \ \[errorInfo\ \$err\ \$errorInfo\]\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text-html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>folk:\ 500\ Internal\ Server\ Error</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \$err\]:\n\[htmlEscape\ \[errorInfo\ \$err\ \$errorInfo\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 500\ Internal\ Server\ Error\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ statusAndHeaders\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$response\ body\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[regexp\ \{POST\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\}\ \{\n\ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ set\ contentType\ \"text/plain\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"\$httpStatus\\r\\nConnection:\ close\\r\\nContent-Type:\ \$contentType\\r\\n\\r\\n\"\n\n\ \ \ \ \ \ \ \ set\ body\ \[\$chan\ read\ \[headerGet\ \$headers\ Content-Length\]\]\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ (\$body)\"\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[eval\ \$body\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[info\ exists\ path\]\ &&\ \$path\ eq\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"web:\ Request\ for\ /ws\ (\$headers)\"\n\ \ \ \ \ \ \ \ set\ clientKey\ \[headerGet\ \$headers\ Sec-WebSocket-Key\ \"\"\]\n\ \ \ \ \ \ \ \ if\ \{\$clientKey\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"HTTP/1.1\ 400\ Bad\ Request\\r\\nConnection:\ close\\r\\nContent-Type:\ text/plain\;\ charset=utf-8\\r\\n\\r\\nMissing\ Sec-WebSocket-Key\\r\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ WsConnection\ upgrade\ \$chan\ \$clientKey\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ Retract!\ websocket\ \$chan\ is\ connected\]\n\ \ \ \ \ \ \ \ Assert!\ websocket\ \$chan\ is\ connected\n\n\ \ \ \ \}\ else\ \{\ puts\ \"Closing:\ \$chan\ \$addr\ \$headers\"\;\ close\ \$chan\ \}\n\}\n\nwhile\ true\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[socket\ stream.server\ 4273\]\n\ \ \ \ \ \ \ \ \$f\ listen\ 128\n\ \ \ \ \ \ \ \ \$f\ readable\ \[lambda\ \{\}\ \{f\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ client\ \[\$f\ accept\ addr\]\n\ \ \ \ \ \ \ \ \ \ \ \ handleConnect\ \$client\ \$addr\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ break\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ #\ Handles\ failure\ to\ bind\ to\ :4273.\ We\ try\ again\ in\ a\ second.\n\ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$e\"\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\nvwait\ forever\n\n\}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ puts\ \$::realStderr\ \"WARNING:\ web.folk\ failed\ to\ initialize\;\nthe\ web\ server\ is\ probably\ down\;\ check\ /var/tmp/folk-\[pid\]/\ for\ log\ files.\n(Make\ sure\ libtool\ and\ autoconf-archive\ are\ installed.)\n------------------------------------------\n\[errorInfo\ \$e\]\"\n\ \ \ \ return\ -options\ \$opts\ \$e\n\}\n with environment {{this builtin-programs/web/web.folk}}
when {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
(
[ m565:0 (s891:0) ]
)when {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
}
} with environment {{this builtin-programs/web/quads.folk}}
when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statemen (
[ m568:0 (s890:0) ]
)when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
}
} with environment {{this builtin-programs/web/statements.folk}}
when {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [ (
[ m575:0 (s901:0) ]
)when {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
}
} with environment {{this builtin-programs/web/keyboards.folk}}
when set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ (
[ m589:0 (s1304:0) ]
)when set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ \ \ \ \$cc\ include\ <stdlib.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\ \ \ \ \$cc\ include\ \"trie.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ Db\ Db\;\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ void\ dbLockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ void\ dbUnlockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ Trie*\ dbGetClauseToStatementRef(Db*\ db)\;\n\n#ifdef\ TRACY_ENABLE\n\n#include\ <string.h>\nvoid\ *tmalloc(size_t\ sz)\ \{\n\ \ \ \ void\ *ptr\ =\ malloc(sz)\;\n\ \ \ \ TracyCAllocS(ptr,\ sz,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nvoid\ *tcalloc(size_t\ s1,\ size_t\ s2)\ \{\n\ \ \ \ void\ *ptr\ =\ calloc(s1,\ s2)\;\n\ \ \ \ TracyCAllocS(ptr,\ s1\ *\ s2,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nchar\ *tstrdup(const\ char\ *s0)\ \{\n\ \ \ \ int\ sz\ =\ strlen(s0)\ +\ 1\;\n\ \ \ \ char\ *s\ =\ tmalloc(sz)\;\n\ \ \ \ memcpy(s,\ s0,\ sz)\;\n\ \ \ \ return\ s\;\n\}\nvoid\ tfree(void\ *ptr)\ \{\n\ \ \ \ TracyCFreeS(ptr,\ 4)\;\n\ \ \ \ free(ptr)\;\n\}\n\n#else\n\n#define\ tmalloc\ malloc\n#define\ tcalloc\ calloc\n#define\ tstrdup\ strdup\n#define\ tfree\ free\n\n#endif\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ tclify\ \{Trie*\ trie\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ objc\ =\ 3\ +\ trie->branchesCount\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ objv\[objc\]\;\n\ \ \ \ \ \ \ \ objv\[0\]\ =\ Jim_ObjPrintf(\"x%\"\ PRIxPTR,\ (uintptr_t)\ trie)\;\n\ \ \ \ \ \ \ \ objv\[1\]\ =\ trie->key\ ?\ Jim_ObjPrintf(\"%s\",\ trie->key)\ :\ Jim_ObjPrintf(\"ROOT\")\;\n\ \ \ \ \ \ \ \ objv\[2\]\ =\ trie->value\ ?\ Jim_ObjPrintf(\"%\"PRIu64,\ trie->value)\ :\ Jim_ObjPrintf(\"NULL\")\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ trie->branchesCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ HACK:\ const\ isn't\ supported\ yet,\ so\ have\ to\ cast.\n\ \ \ \ \ \ \ \ \ \ \ \ objv\[3+i\]\ =\ trie->branches\[i\]\ ?\ tclify((Trie\ *)trie->branches\[i\])\ :\ Jim_NewStringObj(interp,\ \"\",\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ objv,\ objc)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ dbTrieTclify\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ dbLockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Trie*\ trie\ =\ dbGetClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ tclify(trie)\;\n\ \ \ \ \ \ \ \ dbUnlockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ jimObjToClause\ \{Jim_Obj*\ clauseObj\}\ Clause*\ \{\n\ \ \ \ \ \ \ \ int\ nTerms\ =\ Jim_ListLength(interp,\ clauseObj)\;\n\ \ \ \ \ \ \ \ Clause*\ clause\ =\ clauseNew(nTerms)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ termObj\ =\ Jim_ListGetIndex(interp,\ clauseObj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ termLen\;\n\ \ \ \ \ \ \ \ \ \ \ \ const\ char*\ termStr\ =\ Jim_GetString(termObj,\ &termLen)\;\n\ \ \ \ \ \ \ \ \ \ \ \ clause->terms\[i\]\ =\ termNew(termStr,\ termLen)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ clause\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ clauseToJimObj\ \{Clause*\ clause\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ termObjs\[clause->nTerms\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ clause->nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ termObjs\[i\]\ =\ Jim_NewStringObj(interp,\ termPtr(clause->terms\[i\]),\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ termLen(clause->terms\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ termObjs,\ clause->nTerms)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ new\ \{\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieNew()\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ add\ \{Trie*\ trie\ Jim_Obj*\ patternObj\ uint64_t\ value\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieAdd(trie,\ tmalloc,\ tfree,\ pattern,\ value)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ lookup\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\ =\ trieLookup(trie,\ pattern,\ results,\ 50)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultObjs\[resultCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ resultObjs\[i\]\ =\ Jim_NewIntObj(interp,\ results\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ resultObjs,\ resultCount)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ remove_\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\;\n\ \ \ \ \ \ \ \ trie\ =\ (Trie\ *)trieRemove(trie,\ tmalloc,\ tfree,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pattern,\ results,\ 50,\ &resultCount)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\ \ \ \ \ \ \ \ return\ trie\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nset\ trieDotify\ \{\{trieLib\ tclifiedTrie\}\ \{\n\ \ \ \ local\ proc\ idify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ generate\ id-able\ word\ by\ eliminating\ all\ non-alphanumeric\n\ \ \ \ \ \ \ \ regsub\ -all\ \{\\W+\}\ \$word\ \"_\"\n\ \ \ \ \}\n\ \ \ \ local\ proc\ labelify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ shorten\ the\ longest\ lines\n\ \ \ \ \ \ \ \ set\ word\ \[join\ \[lmap\ line\ \[split\ \$word\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$word\]\n\ \ \ \ \}\n\ \ \ \ local\ proc\ subdot\ \{subtrie\}\ \{\n\ \ \ \ \ \ \ \ set\ branches\ \[lassign\ \$subtrie\ ptr\ key\ id\]\n\n\ \ \ \ \ \ \ \ set\ dot\ \[list\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ \\\[label=\\\"\[labelify\ \$key\]\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ branch\ \$branches\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$branch\ eq\ \{\}\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ branchptr\ \[lindex\ \$branch\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ ->\ \$branchptr\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \[subdot\ \$branch\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[join\ \$dot\ \"\\n\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[subdot\ \$tclifiedTrie\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWish\ the\ web\ server\ handles\ route\ \{/trie-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\}\n with environment {{this builtin-programs/web/trie-graph.folk}}
when Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ th (
[ m590:0 (s920:0) ]
)when Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n with environment {{this builtin-programs/web/page.folk}}
when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomical (
[ m598:0 (s931:0) ]
)when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
}
} with environment {{this builtin-programs/web/atomicallys.folk}}
when Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ (
[ m604:0 (s940:0) ]
)when Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ handler\ \{\n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/web/new.folk}}
when {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [str (
[ m612:0 (s951:0) ]
)when {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
}
} with environment {{this builtin-programs/web/log.folk}}
when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/ (
[ m620:0 (s962:0) ]
)when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/web/camera-frame.folk}}
when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/ (
[ m626:0 (s971:0) ]
)when When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/web/apriltag-frame.folk}}
when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" (
[ m632:0 (s980:0) ]
)when {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
}
} with environment {{this builtin-programs/web/report.folk}}
when {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! (
[ m638:0 (s989:0) ]
)when {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
}
} with environment {{this builtin-programs/web/printed-programs.folk}}
when Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{ (
[ m646:0 (s1000:0) ]
)when Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n with environment {{this builtin-programs/web/index.folk}}
when {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} (
[ m654:0 (s1011:0) ]
)when {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
}
} with environment {{this builtin-programs/web/camera.folk}}
when #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ (
[ m662:0 (s1022:0 s1023:0) ]
)when #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ -\ paper\ edge\ to\ top\ margin\n#\n#\ -\ paper\ edge\ to\ bottom\ margin\n#\n#\ -\ paper\ edge\ to\ left\ margin\n#\n#\ -\ tag\ inner\ width,\ to\ account\ for\ scaling.\ (We\ also\ want\ this\ tag\n#\ \ \ inner\ width\ to\ be\ exactly\ the\ same\ as\ the\ tag\ inner\ width\ that\ we\n#\ \ \ use\ on\ every\ printed\ program,\ so\ that\ if\ the\ user\ measures\ the\ tag\n#\ \ \ wrong,\ it\ still\ looks\ OK\ on\ the\ average\ program.)\n#\n#\ Then\ we\ can\ correct\ for\ these\ factors\ in\ all\ future\ prints,\ so\ we\n#\ can\ print\ mm-accurate.\n\n#\ These\ values\ are\ all\ in\ points\ (1/72\ of\ an\ inch).\nset\ marginTop\ 48\;\ set\ marginLeft\ 48\n\nset\ measureTop\ \[/\ \$marginTop\ 2\]\;\ set\ measureLeft\ \[/\ \$marginLeft\ 2\]\nset\ tagInnerSideLength\ 70\n\nWhen\ the\ calibration\ measurements\ are\ /measurements/\ \{\n\ \ \ \ set\ m_tag\ \[string\ trimright\ \[dict\ get\ \$measurements\ tagSideLength\]\ mm\]\n\ \ \ \ set\ m_left\ \[string\ trimright\ \[dict\ get\ \$measurements\ left\]\ mm\]\n\ \ \ \ set\ m_bottom\ \[string\ trimright\ \[dict\ get\ \$measurements\ bottom\]\ mm\]\n\n\ \ \ \ #\ Derive\ a\ PostScript\ CTM\ that\ maps\ calibrated\ space\ (origin\ at\n\ \ \ \ #\ paper\ bottom-left,\ 1\ unit\ =\ 1\ physical\ point\ =\ 25.4/72\ mm)\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coordinate\ space.\n\ \ \ \ #\n\ \ \ \ #\ The\ calibration\ board\ was\ printed\ unmediated,\ so\ its\ PS\ coords\n\ \ \ \ #\ are\ the\ printer's\ raw\ coords.\ \ The\ measurement\ lines\ were\ drawn\n\ \ \ \ #\ at\ PS\ positions\ measureLeft\ and\ measureTop\;\ the\ tag\ inner\ side\n\ \ \ \ #\ was\ tagInnerSideLength\ PS\ points.\ \ From\ the\ physical\ measurements\n\ \ \ \ #\ (in\ mm)\ we\ can\ recover\ the\ printer's\ scale\ and\ origin\ offset.\n\ \ \ \ set\ scale\ \[expr\ \{25.4\ *\ \$tagInnerSideLength\ /\ (72.0\ *\ \$m_tag)\}\]\n\ \ \ \ set\ tx\ \[expr\ \{\$measureLeft\ -\ \$m_left\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\ \ \ \ set\ ty\ \[expr\ \{\$measureTop\ -\ \$m_bottom\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\n\ \ \ \ Claim\ the\ calibrated\ print\ scale\ is\ \$scale\n\ \ \ \ Claim\ the\ calibrated\ print\ translation\ is\ \[list\ \$tx\ \$ty\]\n\}\n\nWhen\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ \{\n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n\}\n with environment {{this builtin-programs/calibrate/calibration-board.folk}}
when When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobo (
[ m668:0 (s1032:0 s1033:0 s1034:0 s1035:0) ]
)when When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\}\n\nWhen\ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n\}\n\nWhen\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n\}\n\nWhen\ the\ collected\ results\ for\ \{/somebody/\ claims\ the\ default\ program\ geometry\ is\ /geom/\}\ are\ /results/\ \{\n\ \ \ \ set\ defaultGeometry\ \{tagSize\ 30mm\ top\ 28mm\ right\ 28mm\ left\ 157mm\ bottom\ 80mm\}\n\ \ \ \ set\ shouldClaim\ false\n\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\ ||\n\ \ \ \ \ \ \ \ \[llength\ \$results\]\ ==\ 1\ &&\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\ ==\ \$defaultGeometry\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeometry\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/calibrate/load-calibration.folk}}
when a calibration from camera /camera/ to display /display/ is /calibration/ \n\ \ \ \ puts\ \"\\n\\ (
[ m921:0 (s1599:0 s1600:0 s1601:0) ]
)when a calibration from camera /camera/ to display /display/ is /calibration/ \n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n with environment {{this builtin-programs/calibrate/load-calibration.folk} {} {}}
when a calibration from camera /camera/ to display /display/ is /calibration/ {
set calibrati (
[ m1066:0 (s1855:0) ]
)when a calibration from camera /camera/ to display /display/ is /calibration/ {
set calibrationReport "$posesReport
<p>Calibration:</p><pre>
Camera intrinsics --------
[join [lmap {k v} [dict get $calibration camera intrinsics] {list $k $v}] \n]
Camera RMSE [dict getdef $calibration camera rmse (unavailable)]
Projector intrinsics -----
[join [lmap {k v} [dict get $calibration projector intrinsics] {list $k $v}] \n]
Projector RMSE [dict getdef $calibration projector rmse (unavailable)]
----
Stereo RMSE [dict getdef $calibration rmse (unavailable)]
</pre>"
Claim the calibration report is $calibrationReport
} with environment {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 display monitor calibrationPoses {{model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 28 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-75314.698413 4478.401730 19997.029253 }{-971.492484 -71792.210770 22876.355728 }{-1.407849 2.419020 18.216270 }} rmse 0.725728225238 tags {48601 {id 48601 c {1385.029589 373.397601} p {{1367.431885 391.921936} {1405.210205 389.762604} {1402.768921 354.724182} {1364.972778 357.132996}} size 37 angle 0.057096} 48603 {id 48603 c {1538.393435 364.163451} p {{1520.251709 382.996368} {1560.268555 380.483032} {1556.391846 345.479309} {1516.824951 348.072632}} size 40 angle 0.062725} 48604 {id 48604 c {1314.707595 447.429039} p {{1296.983887 465.832520} {1334.821533 464.710083} {1332.746704 428.698059} {1294.883911 430.397369}} size 37 angle 0.029656} 48606 {id 48606 c {1466.610059 439.916687} p {{1448.426758 459.265656} {1487.840576 457.079193} {1484.453857 420.928986} {1445.619263 422.947968}} size 39 angle 0.055418} 48609 {id 48609 c {1394.987112 514.999554} p {{1377.006226 533.712585} {1415.902588 532.740601} {1413.313599 495.926849} {1374.507446 497.628174}} size 38 angle 0.024984} 48611 {id 48611 c {1551.315859 508.245212} p {{1533.442505 527.498169} {1572.451660 526.567932} {1569.045044 489.147552} {1530.549683 490.242920}} size 39 angle 0.023842} 48612 {id 48612 c {1323.958123 589.924482} p {{1306.240601 608.614990} {1344.435791 607.666931} {1341.827026 571.074280} {1303.762695 572.426575}} size 38 angle 0.024816} 48614 {id 48614 c {1479.024930 584.982536} p {{1460.857666 603.967041} {1500.821045 602.853821} {1497.578369 565.594482} {1457.400269 567.251831}} size 39 angle 0.027849} 48617 {id 48617 c {1406.285006 661.290040} p {{1388.146118 680.364746} {1427.638062 679.629700} {1424.388550 642.252502} {1385.154663 643.141663}} size 39 angle 0.018610} 48619 {id 48619 c {1565.543612 657.303678} p {{1547.084473 676.826904} {1587.975098 675.831177} {1583.959351 637.826355} {1543.498535 639.095337}} size 40 angle 0.024346} 48600 {id 48600 c {1311.069046 378.239945} p {{1293.403809 397.174408} {1331.194946 394.612976} {1328.710938 359.330505} {1291.372437 362.216156}} size 37 angle 0.067675} 48602 {id 48602 c {1460.901364 369.680924} p {{1443.130371 388.178741} {1482.119629 386.910889} {1479.017700 350.823639} {1440.809570 353.365692}} size 39 angle 0.032507} 48605 {id 48605 c {1390.772515 444.293298} p {{1372.398560 463.838928} {1411.644775 461.251099} {1408.589966 425.339661} {1369.880737 427.319641}} size 39 angle 0.065843} 48607 {id 48607 c {1544.826101 436.656867} p {{1526.837891 455.811432} {1566.585449 454.317230} {1563.773438 416.480988} {1523.533813 419.375580}} size 39 angle 0.037575} 48608 {id 48608 c {1320.136780 518.359033} p {{1302.109009 537.349243} {1340.637085 535.987244} {1338.151733 499.382324} {1299.486084 500.601501}} size 38 angle 0.035336} 48610 {id 48610 c {1472.920554 512.574182} p {{1454.544067 531.717834} {1494.853027 530.374573} {1491.634033 493.079468} {1451.511475 495.198578}} size 40 angle 0.033312} 48613 {id 48613 c {1401.442760 587.735040} p {{1383.686401 606.712585} {1422.481323 605.905945} {1419.349243 568.597046} {1380.474243 569.624634}} size 38 angle 0.020789} 48615 {id 48615 c {1558.880689 582.530694} p {{1540.743286 601.986816} {1580.547241 600.764343} {1576.885620 563.216675} {1537.027832 564.140259}} size 39 angle 0.030703} 48616 {id 48616 c {1329.655113 663.051861} p {{1311.354126 682.407532} {1350.495972 681.459778} {1347.780396 643.882019} {1309.224487 645.006287}} size 39 angle 0.024209} 48618 {id 48618 c {1486.141093 659.716024} p {{1467.177856 679.632935} {1507.811157 677.993408} {1504.760864 640.159851} {1464.393188 641.372986}} size 40 angle 0.040327}} imageName pose-1781543257841-0.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 43 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1056840.114219 42808.811083 264863.141447 }{32312.866960 -1007364.955709 402770.605979 }{-11.182218 42.695320 245.704300 }} rmse 1.89131853376 tags {48601 {id 48601 c {1395.952641 212.861420} p {{1377.588257 233.639587} {1417.538696 229.658676} {1414.197876 192.218063} {1374.617188 196.259171}} size 40 angle 0.099318} 48603 {id 48603 c {1553.635336 197.600660} p {{1535.305908 218.149307} {1575.980347 214.534927} {1571.934326 177.086136} {1531.557007 180.868500}} size 40 angle 0.088628} 48604 {id 48604 c {1324.137968 293.707576} p {{1306.116943 313.840912} {1345.083008 310.326050} {1341.587646 274.212555} {1303.338867 277.204895}} size 39 angle 0.089960} 48606 {id 48606 c {1480.843873 279.367657} p {{1462.405518 299.948456} {1502.627686 296.394623} {1499.185791 258.894501} {1459.289917 262.520355}} size 40 angle 0.088126} 48609 {id 48609 c {1408.072088 360.901788} p {{1390.102661 380.931671} {1429.527344 377.933807} {1426.243774 340.646454} {1386.851929 344.056396}} size 39 angle 0.075894} 48611 {id 48611 c {1567.259040 347.361196} p {{1549.179443 367.838379} {1588.584595 365.235809} {1584.650513 327.663391} {1546.489990 329.953033}} size 39 angle 0.065951} 48612 {id 48612 c {1336.656619 441.631250} p {{1318.508179 462.043243} {1358.458130 459.201569} {1354.721069 421.313721} {1315.223755 424.358032}} size 40 angle 0.071011} 48614 {id 48614 c {1494.646192 429.683558} p {{1476.802612 449.946777} {1516.712524 447.297180} {1512.817993 409.047607} {1472.774170 412.225037}} size 39 angle 0.066292} 48617 {id 48617 c {1423.249643 510.798629} p {{1404.714844 531.413879} {1445.430786 528.574585} {1441.903687 490.050751} {1400.936401 492.916809}} size 40 angle 0.069622} 48619 {id 48619 c {1583.746862 499.650259} p {{1566.048706 520.226074} {1606.481323 517.599731} {1601.709229 478.767273} {1560.927002 481.633362}} size 40 angle 0.064865} 48600 {id 48600 c {1318.372902 222.551387} p {{1299.982056 243.184250} {1339.737549 239.225800} {1336.857300 201.813568} {1296.936279 205.820801}} size 39 angle 0.099243} 48602 {id 48602 c {1474.613028 207.413025} p {{1456.190552 227.932159} {1496.754761 224.579254} {1493.370117 186.521194} {1452.811646 190.510666}} size 40 angle 0.082469} 48605 {id 48605 c {1402.289206 288.773703} p {{1381.081299 272.196045} {1383.976074 309.481049} {1423.905273 305.670410} {1420.299072 268.409271}} size 37 angle -1.493313} 48607 {id 48607 c {1560.824988 274.287257} p {{1542.879883 294.537292} {1582.193848 292.009033} {1578.751343 254.058380} {1539.623535 256.704315}} size 39 angle 0.064221} 48608 {id 48608 c {1330.693159 369.828011} p {{1312.406006 390.445038} {1352.469727 386.978882} {1349.092041 349.085022} {1309.401855 353.059326}} size 40 angle 0.086301} 48610 {id 48610 c {1488.474183 356.547666} p {{1469.599854 377.690796} {1510.819702 373.957123} {1506.693237 336.138580} {1466.973022 339.796051}} size 41 angle 0.090333} 48613 {id 48613 c {1416.229342 437.995789} p {{1394.115112 420.463196} {1397.874268 459.000122} {1438.656128 455.776184} {1434.263916 417.358215}} size 38 angle -1.473557} 48615 {id 48615 c {1575.955360 426.006059} p {{1557.106689 447.186432} {1598.870117 444.503754} {1594.429932 405.246063} {1553.894043 408.197296}} size 41 angle 0.064147} 48616 {id 48616 c {1344.023531 519.212660} p {{1325.910889 539.723450} {1366.120361 537.195007} {1362.370117 498.436951} {1322.228394 501.475830}} size 40 angle 0.062799} 48618 {id 48618 c {1504.497483 507.714315} p {{1485.648682 528.901550} {1527.599365 526.065979} {1523.404175 486.462006} {1481.829468 489.707306}} size 42 angle 0.067490}} imageName pose-1781543257841-1.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 64 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-209693.666866 32261.725933 45616.235897 }{9716.750647 -182727.705443 69957.706876 }{1.369661 20.418735 41.956332 }} rmse 1.12427806234 tags {48601 {id 48601 c {1509.711328 54.434227} p {{1480.648926 85.984230} {1536.133667 82.819717} {1538.859497 22.791117} {1483.493286 26.268213}} size 55 angle 0.056972} 48604 {id 48604 c {1394.354083 178.405525} p {{1365.312988 209.825806} {1421.084839 206.090240} {1423.003174 147.409363} {1367.770142 150.872864}} size 55 angle 0.066880} 48606 {id 48606 c {1610.914251 165.377982} p {{1581.291260 195.974930} {1636.133911 193.269714} {1640.511963 134.807144} {1585.921265 137.736938}} size 54 angle 0.049287} 48609 {id 48609 c {1495.829713 283.255061} p {{1467.725464 311.925690} {1520.545898 308.731995} {1524.365112 254.144592} {1470.828369 257.484192}} size 52 angle 0.060390} 48611 {id 48611 c {1706.065596 270.965025} p {{1678.112183 299.655853} {1728.069824 296.962830} {1733.845215 242.452576} {1684.113159 245.028412}} size 50 angle 0.053854} 48612 {id 48612 c {1385.763556 396.781625} p {{1358.841064 424.564758} {1411.064087 421.179443} {1412.717529 368.966003} {1360.271606 372.199219}} size 52 angle 0.064734} 48614 {id 48614 c {1592.767882 384.014632} p {{1565.013916 411.650513} {1615.941650 408.255951} {1620.917480 355.984802} {1568.793213 358.935516}} size 51 angle 0.066556} 48617 {id 48617 c {1484.082987 492.101955} p {{1456.933105 518.884766} {1508.521606 515.551514} {1511.408203 465.146179} {1459.290771 468.313110}} size 51 angle 0.064523} 48619 {id 48619 c {1684.106845 479.581249} p {{1656.806152 506.011230} {1707.054565 503.155701} {1711.697510 452.870544} {1661.051270 455.895996}} size 50 angle 0.056767} 48600 {id 48600 c {1399.789822 59.409994} p {{1369.518433 92.648804} {1426.722534 87.997520} {1428.329834 28.072285} {1372.388428 30.324989}} size 57 angle 0.081132} 48602 {id 48602 c {1620.425256 46.876868} p {{1590.636230 78.148476} {1645.181152 75.500832} {1650.330200 15.483572} {1595.297729 17.823208}} size 54 angle 0.048503} 48605 {id 48605 c {1502.972095 171.263498} p {{1473.294922 202.666061} {1529.038208 199.092056} {1532.439453 140.082947} {1476.357422 142.849289}} size 55 angle 0.064028} 48607 {id 48607 c {1716.798563 158.749720} p {{1687.903442 188.728394} {1740.135620 186.814194} {1747.215942 127.191704} {1692.823486 129.917984}} size 52 angle 0.036632} 48608 {id 48608 c {1389.683476 289.345012} p {{1361.929688 318.369263} {1415.511719 314.445282} {1418.558594 259.148102} {1363.436646 263.837952}} size 53 angle 0.073103} 48610 {id 48610 c {1601.362012 276.392144} p {{1572.501587 305.586060} {1625.155640 301.927612} {1630.324951 247.094528} {1577.106812 250.361313}} size 52 angle 0.069369} 48613 {id 48613 c {1489.824889 389.421889} p {{1462.307617 417.067352} {1514.499268 414.530518} {1517.472290 361.645691} {1465.068970 364.230286}} size 52 angle 0.048568} 48615 {id 48615 c {1694.785648 376.578606} p {{1666.799194 404.401581} {1716.849487 401.537170} {1721.927124 349.595673} {1672.444946 351.306854}} size 50 angle 0.057168} 48616 {id 48616 c {1381.972820 497.565982} p {{1355.683105 523.804565} {1407.246094 521.063721} {1409.440552 470.151672} {1356.126343 473.535309}} size 51 angle 0.053105} 48618 {id 48618 c {1585.154532 484.068682} p {{1557.027588 511.571320} {1609.122559 507.884888} {1612.781616 457.054810} {1561.358398 460.423279}} size 52 angle 0.070646}} imageName pose-1781543257841-2.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 84 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{98796.033601 -6946652.610637 2196614.745495 }{6739896.207720 460527.950943 1149462.297906 }{-190.312892 -80.550321 1480.650980 }} rmse 1.96923416025 tags {48601 {id 48601 c {1194.241663 327.654893} p {{1222.111084 348.784912} {1216.369019 300.245178} {1166.462280 306.593140} {1172.062500 355.128784}} size 48 angle 1.688545} 48603 {id 48603 c {1171.725758 137.153038} p {{1199.847046 158.204208} {1193.673950 110.035004} {1143.998901 116.397133} {1149.260986 164.909332}} size 48 angle 1.698256} 48604 {id 48604 c {1308.752097 412.254488} p {{1338.622192 434.530487} {1331.861450 384.154022} {1279.358032 390.333496} {1285.766602 440.204346}} size 50 angle 1.704204} 48606 {id 48606 c {1282.569227 218.915396} p {{1311.468262 240.157288} {1305.318115 190.902405} {1253.950073 197.879227} {1260.240479 246.411026}} size 49 angle 1.695017} 48609 {id 48609 c {1397.995160 301.536987} p {{1428.077271 322.549194} {1420.253662 274.268646} {1368.598511 281.003571} {1375.678467 328.876617}} size 48 angle 1.731445} 48611 {id 48611 c {1370.183598 111.469475} p {{1399.739502 131.376297} {1391.639771 85.337204} {1341.105835 91.884697} {1348.329224 138.086731}} size 46 angle 1.744946} 48612 {id 48612 c {1519.304013 386.697516} p {{1550.766846 409.180939} {1541.709717 358.774933} {1489.093506 365.109009} {1495.861572 415.912109}} size 51 angle 1.748583} 48614 {id 48614 c {1486.619487 192.485437} p {{1517.266602 213.760712} {1508.706177 165.099457} {1456.419800 171.520767} {1463.944824 220.600464}} size 49 angle 1.744933} 48617 {id 48617 c {1607.958935 275.600540} p {{1639.266846 297.007874} {1629.765137 248.022018} {1577.122803 254.515793} {1586.114258 303.227722}} size 49 angle 1.762386} 48619 {id 48619 c {1571.899693 85.866461} p {{1602.301147 106.652153} {1592.920166 59.605083} {1542.627441 65.852814} {1550.401001 112.725288}} size 47 angle 1.767611} 48600 {id 48600 c {1206.794202 426.590988} p {{1236.492432 449.318146} {1229.803345 398.072601} {1177.802734 404.404694} {1183.689575 455.227722}} size 51 angle 1.700593} 48602 {id 48602 c {1184.021152 232.821101} p {{1212.459473 253.815598} {1207.137085 204.863739} {1155.541260 211.795914} {1161.424805 260.150055}} size 49 angle 1.679098} 48605 {id 48605 c {1296.399419 316.668400} p {{1325.864990 337.833160} {1318.705078 289.045715} {1267.292847 295.761505} {1274.157593 344.212036}} size 49 angle 1.716513} 48607 {id 48607 c {1272.569361 125.751695} p {{1301.373169 146.699203} {1294.984741 99.184029} {1244.206299 105.124718} {1249.886353 152.636566}} size 47 angle 1.704445} 48608 {id 48608 c {1414.667729 402.124332} p {{1445.368042 424.986145} {1437.862793 373.319275} {1384.357422 379.552948} {1391.050537 431.453613}} size 52 angle 1.715050} 48610 {id 48610 c {1385.344625 207.908486} p {{1415.355225 229.484650} {1408.298096 180.034698} {1355.682983 186.583206} {1362.748413 235.348434}} size 49 angle 1.712552} 48613 {id 48613 c {1504.010825 290.592138} p {{1535.192505 311.400970} {1525.939331 263.201904} {1472.870605 269.810974} {1482.175293 317.866241}} size 49 angle 1.760467} 48615 {id 48615 c {1472.653357 100.909178} p {{1503.442139 121.380783} {1494.246338 74.729080} {1443.124634 81.275391} {1450.703613 127.521828}} size 47 angle 1.765417} 48616 {id 48616 c {1627.703024 377.014268} p {{1659.892212 399.384186} {1649.839233 348.795959} {1595.999512 354.981873} {1604.796143 406.214996}} size 51 angle 1.766962} 48618 {id 48618 c {1590.935498 182.266953} p {{1622.018433 204.144791} {1613.073486 154.467285} {1560.334961 160.728653} {1568.566406 210.356827}} size 50 angle 1.748948}} imageName pose-1781543257841-3.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 99 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-164.252607 -820.689643 321.050974 }{657.240586 2.194841 74.671280 }{-0.091003 -0.007578 0.199975 }} rmse 1.60197092768 tags {48601 {id 48601 c {1141.550955 582.403096} p {{1161.815552 600.761658} {1163.238403 562.024231} {1120.927490 563.719421} {1120.484253 602.198669}} size 38 angle 1.534082} 48603 {id 48603 c {1145.788283 418.406845} p {{1167.404541 439.410339} {1168.944092 395.168213} {1123.939575 397.177490} {1122.794189 441.483185}} size 44 angle 1.536012} 48604 {id 48604 c {1221.678530 654.892956} p {{1241.052490 672.530945} {1243.321289 635.811279} {1201.962158 636.943237} {1200.216064 673.815674}} size 36 angle 1.509088} 48606 {id 48606 c {1229.823309 499.788624} p {{1250.237061 519.468994} {1253.126953 477.784363} {1208.700195 479.424377} {1206.813232 521.515686}} size 41 angle 1.501580} 48609 {id 48609 c {1309.572061 576.229695} p {{1329.272949 595.172302} {1332.628296 555.744568} {1289.946289 557.359314} {1286.864502 596.405029}} size 39 angle 1.485900} 48611 {id 48611 c {1324.503629 410.281911} p {{1345.424316 431.919800} {1348.665894 386.653442} {1303.432983 388.488922} {1300.430908 433.822815}} size 45 angle 1.499307} 48612 {id 48612 c {1386.199225 649.691146} p {{1405.200684 668.071045} {1409.600952 630.438660} {1367.856934 631.948853} {1363.365601 668.476257}} size 37 angle 1.454397} 48614 {id 48614 c {1404.546747 492.311979} p {{1424.596436 512.734863} {1429.509399 470.110352} {1384.809814 472.207672} {1379.893799 514.238159}} size 42 angle 1.456041} 48617 {id 48617 c {1481.319865 570.522647} p {{1500.176636 589.614075} {1506.079590 549.730896} {1462.400513 551.367859} {1457.022339 590.926270}} size 40 angle 1.423857} 48619 {id 48619 c {1505.624037 402.192051} p {{1525.058838 423.735840} {1531.934570 378.371429} {1485.980469 380.416840} {1479.559814 425.789673}} size 45 angle 1.420375} 48600 {id 48600 c {1138.113454 658.341403} p {{1157.728149 676.412109} {1159.237061 639.123474} {1118.033081 639.841675} {1117.274170 677.300659}} size 37 angle 1.530353} 48602 {id 48602 c {1141.823652 502.541629} p {{1163.265625 522.951355} {1164.351807 480.563751} {1119.985718 481.755005} {1119.635254 524.188049}} size 42 angle 1.545177} 48605 {id 48605 c {1223.377045 580.184804} p {{1201.270752 599.937561} {1243.418579 599.076233} {1245.842407 560.111206} {1203.125610 561.095520}} size 42 angle 0.020433} 48607 {id 48607 c {1232.657392 413.568093} p {{1254.376343 435.440247} {1256.473877 390.930359} {1211.246704 392.006378} {1208.927002 436.123993}} size 44 angle 1.523706} 48608 {id 48608 c {1301.878842 653.889951} p {{1320.725586 671.876770} {1324.375000 634.329895} {1282.553223 635.446106} {1278.991821 673.789856}} size 37 angle 1.473904} 48610 {id 48610 c {1314.763363 497.048578} p {{1335.116821 517.577820} {1339.197754 475.334717} {1294.032349 476.138519} {1290.772095 518.368652}} size 42 angle 1.474489} 48613 {id 48613 c {1393.748209 574.806004} p {{1369.902954 595.453003} {1413.156860 593.946838} {1417.280640 554.429871} {1373.905273 555.236877}} size 43 angle 0.034807} 48615 {id 48615 c {1412.617496 407.403562} p {{1433.579224 429.078918} {1438.576172 383.783478} {1391.769043 385.845337} {1387.735352 430.044098}} size 45 angle 1.460922} 48616 {id 48616 c {1468.586555 649.108080} p {{1487.397583 667.221069} {1492.819580 629.765076} {1450.277710 631.478638} {1444.668457 668.199707}} size 37 angle 1.427038} 48618 {id 48618 c {1491.469528 490.510814} p {{1510.942993 511.321289} {1517.885132 468.175201} {1472.139771 469.853912} {1465.745728 512.261475}} size 43 angle 1.411265}} imageName pose-1781543257841-4.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 113 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-652.045996 -21.596042 316.832491 }{38.585632 -605.150208 263.674429 }{-0.025238 0.018629 0.147826 }} rmse 2.01227215325 tags {48601 {id 48601 c {977.930902 159.133678} p {{961.526062 180.890030} {998.662842 173.187088} {994.492188 137.169846} {957.513733 145.293640}} size 37 angle 0.204521} 48603 {id 48603 c {1128.442555 127.285638} p {{1111.380981 149.230835} {1150.937012 141.910492} {1145.978394 104.730423} {1106.935059 113.302460}} size 40 angle 0.182992} 48604 {id 48604 c {913.613811 244.410072} p {{897.504028 265.617676} {933.629150 258.775940} {929.834473 223.056503} {893.546875 230.007172}} size 36 angle 0.187173} 48606 {id 48606 c {1061.222644 215.459666} p {{1044.215210 237.679565} {1082.993774 230.328522} {1078.232056 193.237183} {1039.661499 200.734222}} size 39 angle 0.187342} 48609 {id 48609 c {994.600018 302.540949} p {{978.372559 323.581116} {1015.690918 317.462067} {1011.314331 280.869537} {973.992737 287.961975}} size 37 angle 0.162523} 48611 {id 48611 c {1148.040286 274.979104} p {{1130.848511 296.855865} {1170.356934 290.619507} {1165.280518 253.040680} {1125.903931 259.465057}} size 39 angle 0.156557} 48612 {id 48612 c {929.044403 388.400978} p {{912.621643 409.819275} {949.752258 403.972961} {945.610474 366.795776} {909.082642 373.390045}} size 37 angle 0.156171} 48614 {id 48614 c {1079.629903 363.319986} p {{1062.534424 385.340088} {1101.736694 378.890747} {1096.727173 341.297577} {1058.058228 348.126129}} size 39 angle 0.163054} 48617 {id 48617 c {1011.995130 450.385611} p {{994.765564 472.561249} {1033.851685 466.870331} {1029.125000 428.338287} {990.725464 434.343536}} size 39 angle 0.144583} 48619 {id 48619 c {1168.522487 426.853393} p {{1150.667725 449.554413} {1191.837036 443.555511} {1186.205078 404.371277} {1145.656982 410.472961}} size 41 angle 0.144695} 48600 {id 48600 c {906.411835 177.815006} p {{889.984741 199.787430} {926.487671 191.674118} {922.554993 156.222366} {886.374207 163.982269}} size 37 angle 0.218709} 48602 {id 48602 c {1051.843604 146.397340} p {{1034.971924 168.697723} {1073.739624 160.711548} {1068.651978 124.180634} {1030.366455 132.356964}} size 39 angle 0.203159} 48605 {id 48605 c {986.661165 233.698148} p {{1007.705933 248.093491} {1003.319397 211.708145} {965.541809 219.251785} {970.112244 255.543854}} size 36 angle 1.690775} 48607 {id 48607 c {1137.807079 202.742391} p {{1120.361816 225.086212} {1160.317017 218.317123} {1155.167358 180.507416} {1115.311768 187.177780}} size 40 angle 0.167823} 48608 {id 48608 c {922.560991 318.546825} p {{906.624146 340.189362} {942.870178 333.020996} {938.391785 297.048309} {902.168701 304.013428}} size 36 angle 0.195250} 48610 {id 48610 c {1070.498044 291.328487} p {{1053.658569 313.241547} {1092.294434 306.299133} {1087.534180 269.159515} {1048.903076 276.496185}} size 39 angle 0.177791} 48613 {id 48613 c {1004.548424 378.170736} p {{1026.171143 393.921082} {1021.375305 356.460602} {983.372803 362.746063} {987.668945 399.948730}} size 37 angle 1.698128} 48615 {id 48615 c {1158.497567 351.624066} p {{1141.118408 373.867371} {1181.446045 367.684326} {1175.558594 329.787933} {1136.038452 335.906281}} size 40 angle 0.152136} 48616 {id 48616 c {939.220193 463.734392} p {{922.379578 485.613617} {960.984741 480.247101} {955.976013 441.965332} {918.181152 447.772125}} size 38 angle 0.138125} 48618 {id 48618 c {1090.522811 440.062316} p {{1073.001709 463.023590} {1113.502075 456.692810} {1107.943359 417.232819} {1068.055298 423.802185}} size 40 angle 0.155059}} imageName pose-1781543257841-5.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 127 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-61350.964391 13718.747912 28186.840504 }{4013.252826 -47158.607425 24253.415873 }{0.442939 7.990373 13.206176 }} rmse 2.0423236365 tags {48601 {id 48601 c {995.655720 63.369710} p {{973.477661 90.745377} {1019.583435 88.357903} {1018.224365 35.511921} {971.392822 38.031479}} size 46 angle 0.051736} 48603 {id 48603 c {1180.455537 53.052164} p {{1156.181641 80.391281} {1202.452759 77.794220} {1204.506226 25.964441} {1158.137085 27.948795}} size 46 angle 0.056068} 48604 {id 48604 c {910.089626 169.639338} p {{889.396729 195.435806} {934.235474 192.824677} {931.088196 143.461807} {885.473083 146.002029}} size 44 angle 0.058168} 48606 {id 48606 c {1087.511228 159.278386} p {{1065.120605 184.974594} {1109.740112 182.464233} {1110.227051 133.208969} {1065.099487 135.901810}} size 44 angle 0.056202} 48609 {id 48609 c {1001.921881 257.661450} p {{981.454956 281.020996} {1023.606201 278.443939} {1022.982117 233.624741} {979.547729 236.217819}} size 42 angle 0.061062} 48611 {id 48611 c {1172.079885 247.141943} p {{1150.322266 270.640564} {1191.790283 267.688171} {1194.587402 222.833420} {1151.829712 226.033051}} size 41 angle 0.071077} 48612 {id 48612 c {922.703804 348.671427} p {{903.591309 370.806976} {944.802917 368.033569} {941.781982 326.575623} {900.360535 329.095367}} size 41 angle 0.067195} 48614 {id 48614 c {1086.742713 338.234140} p {{1066.020996 360.519623} {1107.078979 357.741791} {1107.172485 316.262634} {1066.420776 318.740234}} size 41 angle 0.067553} 48617 {id 48617 c {1007.363271 423.517549} p {{987.993103 444.138885} {1027.957153 441.846527} {1026.905151 402.713409} {987.214966 405.585144}} size 40 angle 0.057298} 48619 {id 48619 c {1165.054318 412.989596} p {{1144.602783 433.873840} {1183.831665 430.969727} {1185.664429 391.943420} {1146.122681 394.861725}} size 39 angle 0.073895} 48600 {id 48600 c {901.093923 70.459400} p {{879.565063 98.831100} {926.215210 95.174049} {922.728394 41.948521} {875.173706 44.958752}} size 46 angle 0.078233} 48602 {id 48602 c {1085.779535 59.660986} p {{1062.445923 87.665062} {1108.789673 85.055267} {1109.044922 31.738792} {1062.930176 34.444141}} size 46 angle 0.056254} 48605 {id 48605 c {997.285938 166.825402} p {{973.270996 143.105530} {975.749329 192.658005} {1021.540161 190.781616} {1018.919434 140.876587}} size 49 angle -1.520824} 48607 {id 48607 c {1173.617485 154.937350} p {{1150.805542 180.724335} {1195.427490 177.985092} {1197.802246 127.598511} {1151.804687 131.886658}} size 44 angle 0.061311} 48608 {id 48608 c {915.100492 265.275558} p {{895.314270 289.225830} {938.357666 286.459778} {935.249207 240.886505} {891.717712 243.976929}} size 43 angle 0.064174} 48610 {id 48610 c {1085.493242 255.170662} p {{1064.236572 278.830505} {1106.522827 275.830505} {1107.605225 230.558807} {1063.488892 233.553192}} size 42 angle 0.070826} 48613 {id 48613 c {1003.760979 346.516282} p {{982.015869 326.394714} {984.393250 368.502594} {1025.032593 366.199707} {1023.765808 323.806732}} size 42 angle -1.514397} 48615 {id 48615 c {1167.279457 334.932959} p {{1146.137329 356.945221} {1186.635132 354.646179} {1188.529785 312.808044} {1147.281250 314.565338}} size 40 angle 0.056709} 48616 {id 48616 c {927.208690 432.071257} p {{908.725525 452.526123} {949.156921 450.607025} {946.694458 410.506836} {905.706055 413.911804}} size 40 angle 0.047430} 48618 {id 48618 c {1085.678921 420.576598} p {{1065.630981 441.996979} {1105.944946 439.000702} {1105.520752 399.376434} {1065.620117 402.340881}} size 40 angle 0.074187}} imageName pose-1781543257841-6.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 139 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1293234.230097 -236546.444378 661933.879650 }{123504.689570 -1164505.518365 389497.399567 }{-24.466768 -74.390643 296.571025 }} rmse 1.41663092406 tags {48601 {id 48601 c {949.478206 319.501544} p {{930.948975 336.128265} {970.724487 329.256683} {967.531921 303.301514} {928.905212 310.055542}} size 40 angle 0.171071} 48603 {id 48603 c {1108.382342 293.125748} p {{1091.457397 309.351135} {1132.334351 302.969696} {1125.304199 276.903320} {1085.332153 283.652435}} size 41 angle 0.154863} 48604 {id 48604 c {873.740912 387.403626} p {{853.658752 405.510284} {894.607117 398.498199} {893.467712 369.617371} {852.656311 376.192932}} size 41 angle 0.169597} 48606 {id 48606 c {1038.223024 362.779168} p {{1020.033813 380.388397} {1062.753662 374.629364} {1056.753296 344.839752} {1015.530884 351.817108}} size 43 angle 0.134001} 48609 {id 48609 c {962.427428 434.368246} p {{941.884705 454.018036} {986.398438 446.855377} {982.145691 415.507080} {938.896179 422.110199}} size 45 angle 0.159541} 48611 {id 48611 c {1138.240590 411.331288} p {{1119.195923 430.997711} {1164.848633 424.473511} {1155.939697 393.054352} {1111.961914 398.351746}} size 46 angle 0.141948} 48612 {id 48612 c {878.276910 515.929814} p {{855.905457 537.082336} {902.737427 530.844604} {900.828247 494.607208} {855.529419 502.059540}} size 47 angle 0.132415} 48614 {id 48614 c {1062.340061 487.695207} p {{1041.345215 509.091980} {1089.702148 502.621124} {1082.033081 467.625183} {1035.657471 473.139954}} size 48 angle 0.133024} 48617 {id 48617 c {977.755158 575.323222} p {{955.283936 598.861938} {1005.151978 591.779480} {999.932617 552.092224} {951.709961 559.678833}} size 50 angle 0.141080} 48619 {id 48619 c {1175.241702 547.766057} p {{1155.157227 570.688110} {1206.051147 564.145264} {1194.967285 525.253601} {1145.051514 531.716064}} size 51 angle 0.127857} 48600 {id 48600 c {869.726321 330.031056} p {{850.153198 347.147217} {890.231140 340.157562} {888.217468 313.861053} {849.431213 320.008118}} size 40 angle 0.172665} 48602 {id 48602 c {1027.292091 304.874545} p {{1009.680237 321.058594} {1050.356445 314.883850} {1045.061035 288.546143} {1005.118835 295.251953}} size 41 angle 0.150652} 48605 {id 48605 c {954.464210 373.169764} p {{932.091919 362.031342} {934.827820 391.160309} {977.714783 384.745453} {973.484131 355.744019}} size 29 angle -1.477147} 48607 {id 48607 c {1121.511416 347.373795} p {{1103.990112 365.026520} {1147.302490 359.805634} {1139.057983 329.695618} {1097.288696 335.697937}} size 43 angle 0.119962} 48608 {id 48608 c {874.893165 446.438284} p {{853.459473 466.811462} {898.051331 459.668365} {895.612122 426.744476} {852.912964 433.881165}} size 45 angle 0.158839} 48610 {id 48610 c {1049.016566 421.271853} p {{1029.286255 440.778168} {1074.801270 434.455658} {1068.158569 402.347168} {1023.870789 408.414734}} size 45 angle 0.138027} 48613 {id 48613 c {968.935134 500.034932} p {{943.878113 485.345337} {947.116699 521.777832} {995.350952 515.521118} {990.469421 478.575195}} size 36 angle -1.482137} 48615 {id 48615 c {1154.787958 474.180003} p {{1135.341919 495.410980} {1184.017578 489.054199} {1173.784912 453.439331} {1126.531982 459.801270}} size 49 angle 0.129860} 48616 {id 48616 c {880.531426 588.127394} p {{856.710999 611.316040} {906.284851 605.006714} {904.167236 565.118469} {855.683960 571.841858}} size 49 angle 0.126591} 48618 {id 48618 c {1075.733811 560.537017} p {{1054.046997 584.490234} {1104.965942 577.225769} {1096.608521 537.480774} {1047.277100 544.290955}} size 51 angle 0.141711}} imageName pose-1781543257841-7.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 158 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-3671321.265916 -136949.507711 2544618.126158 }{710108.103504 -4109714.560197 1388714.600088 }{203.442819 176.896104 872.758912 }} rmse 1.7736504896 tags {48601 {id 48601 c {642.392194 133.357953} p {{617.967773 158.737991} {672.279236 157.610672} {666.108459 108.713776} {612.277710 108.920670}} size 54 angle 0.020754} 48603 {id 48603 c {844.852518 132.784390} p {{822.703674 157.752472} {871.943237 155.121231} {865.329102 109.701424} {816.836548 109.684662}} size 49 angle 0.053387} 48604 {id 48604 c {544.373174 234.091164} p {{518.562195 260.513550} {575.344910 258.714539} {570.413330 207.434174} {512.823120 209.008011}} size 56 angle 0.031672} 48606 {id 48606 c {758.088901 229.356579} p {{735.210571 254.415009} {786.411987 252.761688} {780.482178 204.829422} {728.771057 205.129440}} size 51 angle 0.032279} 48609 {id 48609 c {665.531838 330.499630} p {{641.712585 356.745972} {695.350830 354.274567} {689.092102 304.538666} {635.630066 306.658691}} size 53 angle 0.046043} 48611 {id 48611 c {868.893259 319.759095} p {{847.957031 344.389862} {895.765808 342.600800} {889.633667 295.358704} {841.706055 296.649933}} size 47 angle 0.037404} 48612 {id 48612 c {567.420051 439.360050} p {{541.064819 468.426208} {599.423706 463.539520} {593.042664 411.101868} {535.535828 415.270813}} size 58 angle 0.083540} 48614 {id 48614 c {782.684121 422.996243} p {{759.732910 450.327362} {812.032654 445.964630} {805.213684 396.167236} {753.646423 400.271118}} size 52 angle 0.083225} 48617 {id 48617 c {690.240621 532.690635} p {{665.525635 561.614380} {720.572815 555.544250} {714.737122 504.022583} {659.297363 509.376617}} size 55 angle 0.109828} 48619 {id 48619 c {894.948644 511.727718} p {{873.199768 539.352783} {923.236877 534.105225} {916.227539 484.699615} {866.586121 489.291443}} size 50 angle 0.104491} 48600 {id 48600 c {534.750759 135.390685} p {{508.569702 161.553513} {566.256531 161.074783} {560.640137 109.519333} {502.975861 109.487190}} size 57 angle 0.008299} 48602 {id 48602 c {746.947710 134.937998} p {{723.971497 159.439575} {776.209045 159.769836} {769.576782 110.806610} {717.985352 110.359879}} size 52 angle -0.006322} 48605 {id 48605 c {655.668106 233.310392} p {{680.179504 207.696640} {624.799927 208.207703} {631.000854 259.087006} {685.842834 257.849152}} size 55 angle -3.132365} 48607 {id 48607 c {856.791753 227.330298} p {{835.554993 251.461700} {884.879150 251.208878} {878.426758 202.746368} {829.209656 203.881302}} size 49 angle 0.005126} 48608 {id 48608 c {556.857705 337.416902} p {{531.402344 365.235870} {588.602234 361.786133} {581.787415 310.172394} {524.963501 312.932770}} size 57 angle 0.060237} 48610 {id 48610 c {771.564042 327.611774} p {{749.380554 353.552917} {799.942505 350.367218} {793.670471 301.760742} {742.782227 304.532898}} size 50 angle 0.062923} 48613 {id 48613 c {680.121954 433.080485} p {{704.556458 405.732422} {649.144653 409.019745} {654.927063 461.279602} {711.183899 457.206970}} size 55 angle -3.082337} 48615 {id 48615 c {882.796758 417.159998} p {{860.786133 443.784180} {911.162842 440.625854} {903.889832 391.645691} {854.756836 393.963959}} size 50 angle 0.062612} 48616 {id 48616 c {580.346089 546.081070} p {{553.940918 575.834351} {612.320435 569.507202} {606.885620 516.176392} {547.775391 522.218018}} size 58 angle 0.107958} 48618 {id 48618 c {796.660210 523.128245} p {{773.319641 551.862793} {825.849243 545.705505} {819.719788 494.739624} {766.974731 500.166992}} size 52 angle 0.116683}} imageName pose-1781543257841-8.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 237 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1891.405861 1041.655384 2016.225692 }{520.247195 -2581.867798 882.220288 }{0.314318 0.305814 0.589245 }} rmse 3.33980752481 tags {48601 {id 48601 c {364.371225 154.206433} p {{331.795715 179.574631} {398.034821 189.569305} {395.756592 129.765060} {330.482635 118.607208}} size 66 angle -0.149758} 48603 {id 48603 c {596.617941 193.608417} p {{569.365417 215.626068} {621.879395 224.079178} {623.512268 171.880157} {570.107422 161.631012}} size 53 angle -0.159600} 48604 {id 48604 c {233.031368 256.033977} p {{198.913910 282.412262} {268.121460 288.495392} {267.337982 229.509445} {195.164581 221.003876}} size 69 angle -0.087672} 48606 {id 48606 c {486.550832 282.978654} p {{457.602051 306.474640} {514.791077 312.368927} {514.793640 260.055664} {457.518707 252.764252}} size 57 angle -0.102704} 48609 {id 48609 c {369.163334 379.775009} p {{338.807770 404.953491} {400.322906 407.798096} {398.998322 355.028320} {336.650604 350.534973}} size 61 angle -0.046209} 48611 {id 48611 c {592.702856 393.589059} p {{566.986328 416.086365} {617.135071 418.671417} {617.891846 371.553253} {567.347168 367.558655}} size 50 angle -0.051502} 48612 {id 48612 c {245.957694 484.046393} p {{212.855713 511.161255} {280.776245 510.973358} {278.629791 457.283661} {209.693771 456.001648}} size 67 angle 0.002766} 48614 {id 48614 c {487.158600 485.320641} p {{459.366730 509.293365} {514.243896 509.179474} {514.503540 461.733429} {459.173187 460.668915}} size 54 angle 0.002075} 48617 {id 48617 c {375.237326 583.398845} p {{345.979401 609.102905} {405.023529 605.900635} {403.759338 558.341309} {344.480438 560.163757}} size 59 angle 0.054182} 48619 {id 48619 c {587.942277 574.730119} p {{563.161377 597.582275} {610.900452 594.895813} {611.961670 552.580200} {564.200806 553.876404}} size 47 angle 0.056215} 48600 {id 48600 c {226.374950 127.267377} p {{189.934280 153.998489} {264.650635 164.867844} {262.333344 100.890038} {186.153687 87.755653}} size 75 angle -0.144462} 48602 {id 48602 c {486.868933 171.379722} p {{455.991943 194.898392} {516.005554 204.446930} {517.362671 148.152969} {456.641235 137.074249}} size 60 angle -0.157784} 48605 {id 48605 c {365.335940 265.382087} p {{397.465179 297.087921} {397.123322 241.078461} {331.988190 232.473801} {333.097260 290.030762}} size 56 angle 1.576900} 48607 {id 48607 c {593.918332 292.977820} p {{567.305542 315.167755} {617.385620 319.511688} {620.053650 271.186005} {568.262878 263.969849}} size 50 angle -0.086523} 48608 {id 48608 c {236.291299 366.820416} p {{202.024750 393.381042} {272.369934 397.377472} {269.129639 341.366821} {198.805801 335.071808}} size 70 angle -0.056751} 48610 {id 48610 c {486.311857 383.896561} p {{457.866730 407.818268} {514.040649 410.630219} {514.123901 360.507263} {457.134186 355.766022}} size 56 angle -0.050016} 48613 {id 48613 c {370.907103 480.363625} p {{402.015625 506.210236} {401.381683 455.518799} {338.221100 453.206360} {339.819580 505.708160}} size 50 angle 1.583302} 48615 {id 48615 c {588.610704 483.153853} p {{563.043274 506.112549} {612.937317 506.486633} {613.698975 460.625427} {563.892517 459.445496}} size 49 angle -0.007497} 48616 {id 48616 c {247.747799 583.097366} p {{215.949295 610.146484} {282.119080 607.427429} {278.761658 556.715698} {212.549408 558.181824}} size 66 angle 0.041069} 48618 {id 48618 c {485.557389 575.696389} p {{458.575623 599.804138} {511.779755 597.280396} {512.143311 551.942322} {458.491974 553.418457}} size 53 angle 0.047400}} imageName pose-1781543257841-9.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 271 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-263.442465 -3993.519151 3622.146186 }{3838.120310 362.146076 1127.873075 }{-0.281576 0.033683 0.956437 }} rmse 2.30152949436 tags {48601 {id 48601 c {198.621573 241.319812} p {{222.522720 260.372314} {216.912018 217.634796} {174.017868 221.707275} {181.274582 263.783112}} size 43 angle 1.701333} 48603 {id 48603 c {170.962676 67.695843} p {{197.280319 89.311028} {187.799377 43.787811} {145.962463 47.162689} {153.747971 92.140640}} size 46 angle 1.776127} 48604 {id 48604 c {293.592474 318.039051} p {{317.013885 337.112396} {311.371521 295.126556} {269.805115 298.667694} {276.050354 340.646210}} size 42 angle 1.704383} 48606 {id 48606 c {270.454320 148.843220} p {{295.507935 169.239349} {289.732910 124.954781} {245.201157 128.284637} {251.416473 172.433350}} size 44 angle 1.700472} 48609 {id 48609 c {365.796203 226.761980} p {{389.959595 246.366608} {384.328979 203.366684} {341.377594 206.950287} {347.695770 249.611496}} size 43 angle 1.701000} 48611 {id 48611 c {342.683495 55.350728} p {{366.480438 74.572601} {360.948029 32.722778} {317.286224 34.836197} {324.416443 77.981796}} size 42 angle 1.702231} 48612 {id 48612 c {460.969073 304.179221} p {{484.815125 323.147705} {479.274994 281.422089} {436.590271 284.786957} {443.134369 326.350555}} size 42 angle 1.702800} 48614 {id 48614 c {438.893249 134.686283} p {{463.889557 155.440750} {457.597778 110.989212} {414.331299 114.292465} {420.062805 158.542877}} size 44 angle 1.711405} 48617 {id 48617 c {533.080383 213.173669} p {{557.535583 233.393188} {551.556335 189.925522} {509.016449 193.277649} {514.665344 236.345169}} size 43 angle 1.707495} 48619 {id 48619 c {511.162161 40.181078} p {{535.220459 60.709080} {529.012695 17.277449} {487.738098 20.194244} {492.589447 64.011322}} size 43 angle 1.712767} 48602 {id 48602 c {183.638056 152.018918} p {{209.137878 172.819244} {202.462860 127.247940} {158.109695 131.195312} {165.382980 176.040207}} size 46 angle 1.716236} 48605 {id 48605 c {280.437145 231.136902} p {{261.948456 254.223755} {304.560974 250.985748} {299.074646 207.864227} {256.200226 211.195007}} size 42 angle 0.075841} 48607 {id 48607 c {255.648743 58.022969} p {{280.276367 78.527657} {273.481659 34.840279} {230.918121 37.432526} {237.351044 81.809875}} size 44 angle 1.725090} 48608 {id 48608 c {374.839880 308.191019} p {{398.570862 327.621948} {393.538696 285.166840} {350.828522 288.530518} {356.646088 330.593353}} size 42 angle 1.688775} 48610 {id 48610 c {353.426549 139.437219} p {{378.838562 160.236038} {372.627075 115.518738} {328.744843 119.236130} {334.531097 162.975662}} size 45 angle 1.708819} 48613 {id 48613 c {447.986478 217.436763} p {{429.169769 240.373611} {472.259338 237.322754} {467.006531 194.252045} {423.699921 197.539551}} size 43 angle 0.070685} 48615 {id 48615 c {425.381881 44.997536} p {{449.748932 65.453217} {443.391968 21.960690} {402.644073 25.909575} {406.869446 68.676941}} size 43 angle 1.715931} 48616 {id 48616 c {542.267473 295.145410} p {{565.842590 314.410583} {560.579468 272.551575} {518.264099 275.530273} {524.113098 317.544769}} size 42 angle 1.695874} 48618 {id 48618 c {520.425825 125.529852} p {{545.750671 146.685135} {538.838501 101.829994} {496.323822 105.396080} {501.663605 149.679626}} size 45 angle 1.723693}} imageName pose-1781543257841-10.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 286 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{50.824095 -712.814483 1047.080530 }{1220.638908 279.244176 172.091587 }{-0.050051 0.134620 0.274120 }} rmse 1.70201751052 tags {48601 {id 48601 c {72.271242 414.743317} p {{109.223740 440.646667} {102.671288 390.229553} {35.977558 389.301788} {40.616467 440.268860}} size 50 angle 1.700037} 48603 {id 48603 c {54.034779 217.560069} p {{89.145515 245.273972} {86.687927 196.433075} {16.739708 188.122009} {21.451021 238.642166}} size 48 angle 1.621072} 48604 {id 48604 c {205.449907 509.739067} p {{237.443558 532.384338} {232.669586 485.308655} {172.757889 486.599487} {177.778259 534.575134}} size 47 angle 1.671861} 48606 {id 48606 c {186.127986 322.854836} p {{216.630951 347.064301} {212.562012 302.016602} {154.300674 297.594269} {158.851440 344.357239}} size 45 angle 1.660877} 48609 {id 48609 c {307.253575 416.963510} p {{337.794800 439.960144} {330.584656 395.770905} {277.674011 394.690979} {282.244781 439.680054}} size 44 angle 1.732536} 48611 {id 48611 c {287.998633 243.027042} p {{315.487518 266.903290} {311.848602 224.639084} {259.013916 217.851547} {263.363373 262.020447}} size 42 angle 1.656684} 48612 {id 48612 c {417.887151 502.336126} p {{444.486633 522.683228} {439.543701 480.797607} {390.688629 481.530792} {395.722961 524.379517}} size 42 angle 1.688263} 48614 {id 48614 c {397.370296 335.164383} p {{424.254028 357.527649} {418.144684 316.253967} {370.656311 312.942322} {375.638885 354.945953}} size 41 angle 1.717750} 48617 {id 48617 c {499.446103 419.795104} p {{524.130798 440.142609} {518.483093 400.440186} {474.786102 399.467957} {479.741669 439.828613}} size 40 angle 1.712099} 48619 {id 48619 c {479.151452 262.342380} p {{503.282379 284.006531} {498.348785 245.130402} {454.578003 240.280945} {459.620728 279.853271}} size 39 angle 1.697027} 48600 {id 48600 c {77.699261 512.609928} p {{113.413376 536.890869} {108.199699 486.683990} {41.208942 487.801270} {46.064499 539.500061}} size 50 angle 1.674269} 48605 {id 48605 c {193.944591 415.181222} p {{161.437576 390.916840} {165.369568 439.293060} {226.656128 439.598267} {220.324692 392.921478}} size 48 angle -1.489695} 48607 {id 48607 c {176.552192 230.694903} p {{207.905884 256.611755} {204.110565 210.874542} {143.436234 203.321365} {148.534119 250.845886}} size 45 angle 1.653588} 48608 {id 48608 c {313.934619 506.088315} p {{344.029724 528.150574} {338.209686 483.178070} {283.309875 483.637787} {288.532684 530.062073}} size 45 angle 1.699494} 48610 {id 48610 c {296.282791 329.818533} p {{325.236298 353.672607} {320.333221 310.113373} {267.727356 306.292419} {271.577606 350.060150}} size 43 angle 1.682886} 48613 {id 48613 c {406.646786 419.554464} p {{379.693573 397.918732} {383.775238 440.470154} {433.692444 441.264404} {428.465881 399.601227}} size 42 angle -1.475166} 48615 {id 48615 c {388.513550 253.961729} p {{414.263428 276.515167} {410.385437 236.083435} {362.790558 231.431839} {366.332153 272.093018}} size 40 angle 1.666418} 48616 {id 48616 c {507.837697 501.472006} p {{532.209351 521.014099} {527.509155 481.012390} {482.639832 481.267426} {487.555908 522.566406}} size 40 angle 1.687760} 48618 {id 48618 c {488.165975 341.681269} p {{513.142700 363.443085} {506.917389 323.423706} {463.470276 320.164307} {468.794586 360.542480}} size 40 angle 1.725117}} imageName pose-1781543257841-11.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 310 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{766892.576057 -19515.503279 451640.762142 }{23960.984967 703560.433782 93720.310217 }{49.603996 -23.693156 159.828412 }} rmse 1.83027038725 tags {48601 {id 48601 c {432.038537 553.445692} p {{449.389191 528.153564} {414.490356 532.363770} {415.014954 578.261047} {449.635620 574.586365}} size 35 angle -3.021533} 48603 {id 48603 c {302.262651 569.126614} p {{318.298492 545.140564} {285.711456 548.772949} {287.065430 591.858276} {318.288391 588.834106}} size 32 angle -3.030584} 48604 {id 48604 c {500.794313 450.427968} p {{519.482239 422.830261} {481.857849 429.776672} {483.057526 476.621063} {519.694641 471.039856}} size 38 angle -2.959023} 48606 {id 48606 c {365.341744 472.858152} p {{381.949127 447.837952} {349.402557 453.597107} {349.204224 497.170471} {381.573456 492.472687}} size 33 angle -2.966454} 48609 {id 48609 c {429.053209 371.806219} p {{445.609863 345.667053} {411.475128 352.892456} {412.795074 397.474091} {446.470551 390.547028}} size 34 angle -2.932999} 48611 {id 48611 c {302.674349 398.168756} p {{316.837280 373.322449} {289.007324 380.852509} {288.867432 422.390503} {316.956909 416.264893}} size 28 angle -2.877346} 48612 {id 48612 c {496.276042 264.759201} p {{513.637085 237.214569} {477.861755 246.603622} {479.160706 291.914001} {514.729065 282.952972}} size 36 angle -2.884936} 48614 {id 48614 c {363.212078 299.003323} p {{379.272125 273.819183} {347.609619 282.036316} {347.335876 323.899170} {379.685486 316.917450}} size 32 angle -2.887672} 48617 {id 48617 c {427.922356 195.767095} p {{445.219391 168.574158} {411.057007 178.722443} {411.071198 222.259064} {444.654907 212.677536}} size 35 angle -2.852835} 48619 {id 48619 c {304.872502 233.641435} p {{319.946808 208.123108} {291.097809 217.632965} {290.434784 258.082123} {318.112488 249.028488}} size 30 angle -2.823167} 48600 {id 48600 c {501.221953 543.284653} p {{520.159790 516.529175} {482.061554 521.702759} {482.690491 569.466003} {521.101440 565.676514}} size 38 angle -3.006622} 48602 {id 48602 c {362.055178 560.390636} p {{378.363037 535.925354} {345.495270 539.720520} {345.660431 584.986267} {378.310333 580.680359}} size 33 angle -3.026634} 48605 {id 48605 c {428.911134 460.333650} p {{411.418060 485.897827} {447.390472 480.925568} {447.014984 433.876892} {411.214752 440.614197}} size 36 angle 0.137354} 48607 {id 48607 c {299.170137 480.372077} p {{315.152313 456.267578} {284.449646 461.873840} {283.119354 504.580048} {315.378815 500.740417}} size 31 angle -2.960984} 48608 {id 48608 c {497.456230 354.845126} p {{515.249817 326.969238} {479.143768 336.376831} {479.984161 382.217316} {516.885071 374.439301}} size 37 angle -2.886705} 48610 {id 48610 c {362.066778 384.370008} p {{378.052521 358.907959} {345.932373 365.576324} {346.316467 409.457062} {378.003723 402.933685}} size 32 angle -2.936894} 48613 {id 48613 c {426.550325 281.249530} p {{409.839600 307.328125} {444.106659 299.489532} {443.746246 254.413742} {409.587128 263.625763}} size 35 angle 0.224881} 48616 {id 48616 c {495.222277 174.174471} p {{513.788574 145.978683} {477.288757 157.132172} {477.218567 201.515884} {513.863220 191.889038}} size 38 angle -2.845028} 48618 {id 48618 c {362.450130 213.833265} p {{379.252136 187.789291} {346.920319 197.150696} {346.528229 238.513031} {378.182556 230.733490}} size 33 angle -2.859758}} imageName pose-1781543257841-12.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 336 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{4603.471570 134559.198783 47159.825235 }{-135326.500196 5334.233566 57404.380517 }{-0.661932 0.140649 30.635474 }} rmse 1.34260804628 tags {48601 {id 48601 c {1073.750515 175.041853} p {{1052.528687 157.187790} {1052.229614 193.388962} {1095.322754 193.190720} {1094.947021 156.971298}} size 36 angle -1.579058} 48603 {id 48603 c {1074.066976 324.507615} p {{1052.206787 305.428101} {1052.459229 343.463501} {1096.251709 343.870392} {1096.289062 305.012787}} size 38 angle -1.564159} 48604 {id 48604 c {991.370515 107.495040} p {{971.912415 90.922264} {970.732605 125.059685} {1012.167603 125.208252} {1012.146545 89.812843}} size 34 angle -1.605343} 48606 {id 48606 c {988.277975 249.339919} p {{967.488159 230.941681} {966.608826 267.273804} {1009.637512 268.242340} {1010.369141 231.056763}} size 36 angle -1.594994} 48609 {id 48609 c {907.009210 175.727970} p {{887.060913 157.463745} {885.001831 193.691315} {927.278198 194.285812} {928.883423 157.873322}} size 36 angle -1.627573} 48611 {id 48611 c {899.603721 323.934888} p {{878.815857 303.766144} {877.170288 343.879761} {920.487305 344.196503} {922.151794 303.888092}} size 40 angle -1.611796} 48612 {id 48612 c {829.132043 104.562774} p {{810.125427 86.692841} {807.380005 121.667053} {848.812683 123.066422} {850.246216 87.960068}} size 35 angle -1.649134} 48614 {id 48614 c {818.998538 247.498701} p {{798.753723 228.354401} {796.158691 265.858429} {838.737915 266.165039} {841.599487 229.331009}} size 37 angle -1.639880} 48617 {id 48617 c {741.013150 172.140930} p {{721.825806 153.315475} {717.891663 189.537949} {760.464600 191.225510} {763.652710 155.106522}} size 36 angle -1.678983} 48619 {id 48619 c {725.870029 321.457629} p {{706.293152 301.516876} {702.403625 340.028595} {745.532410 341.485474} {749.751099 302.558502}} size 38 angle -1.671451} 48600 {id 48600 c {1074.052102 105.429277} p {{1053.495850 88.308304} {1053.453979 123.142807} {1095.533203 123.320541} {1094.498901 87.845879}} size 34 angle -1.571998} 48602 {id 48602 c {1075.037272 247.719933} p {{1052.954712 228.852646} {1053.197266 266.806152} {1097.088257 266.560242} {1096.558472 228.912323}} size 37 angle -1.564406} 48605 {id 48605 c {991.462856 176.293567} p {{970.636841 157.802673} {969.213196 195.071320} {1012.382080 194.867218} {1013.173828 157.970444}} size 37 angle -1.608977} 48607 {id 48607 c {988.271297 323.409970} p {{966.160828 303.230164} {965.943604 343.330688} {1010.088562 343.322174} {1010.208191 303.837921}} size 40 angle -1.576213} 48608 {id 48608 c {911.985226 106.559502} p {{891.915039 88.722786} {890.529480 123.506119} {931.588745 123.981483} {933.158203 89.836227}} size 34 angle -1.610609} 48610 {id 48610 c {904.876075 247.834935} p {{884.256775 228.930695} {882.191711 266.480865} {925.678406 266.906982} {927.533142 229.211441}} size 37 angle -1.625736} 48613 {id 48613 c {825.474011 173.685320} p {{805.874146 155.010681} {802.850891 191.792252} {845.849548 193.099014} {848.043945 155.620956}} size 36 angle -1.652807} 48615 {id 48615 c {814.123097 321.664336} p {{793.880493 301.762512} {790.620117 341.099457} {835.070190 342.258789} {837.308655 302.491699}} size 39 angle -1.653491} 48616 {id 48616 c {749.620519 102.389401} p {{730.910706 84.664383} {727.124084 119.449913} {768.818787 120.577164} {771.829041 85.547234}} size 34 angle -1.679226} 48618 {id 48618 c {735.360506 244.450282} p {{715.602051 225.177017} {711.425720 262.848114} {755.005920 263.613281} {758.853516 226.392029}} size 37 angle -1.681208}} imageName pose-1781543257841-13.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 349 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-42006.056341 618407.989571 46334.318232 }{-565093.723952 -27983.125273 251552.732742 }{26.922105 54.178774 129.547352 }} rmse 0.738898030151 tags {48601 {id 48601 c {1583.305303 145.282432} p {{1553.724854 133.092209} {1563.607910 174.091873} {1613.596924 157.765732} {1603.335205 115.986664}} size 42 angle -1.334257} 48603 {id 48603 c {1623.495857 309.412621} p {{1593.311890 295.631622} {1603.908203 336.235626} {1654.117798 323.393585} {1643.897461 281.475006}} size 41 angle -1.315523} 48604 {id 48604 c {1471.273914 100.575907} p {{1445.189575 90.033272} {1453.117554 128.696182} {1499.084229 111.816139} {1489.562866 72.250275}} size 39 angle -1.368546} 48606 {id 48606 c {1507.686781 256.319445} p {{1479.963989 243.632904} {1489.166260 282.961151} {1535.705322 269.141327} {1526.807739 228.814011}} size 40 angle -1.340945} 48609 {id 48609 c {1401.802316 207.969095} p {{1376.445190 196.288300} {1384.526978 234.246750} {1427.940308 220.009598} {1419.446411 181.130524}} size 38 angle -1.361017} 48611 {id 48611 c {1435.122709 360.461753} p {{1409.137939 346.993469} {1417.652100 385.808502} {1461.908081 374.345001} {1452.723511 334.926117}} size 39 angle -1.354864} 48612 {id 48612 c {1304.792060 163.544640} p {{1281.339722 152.543762} {1288.938965 189.175308} {1328.660156 174.740540} {1320.708984 137.810776}} size 37 angle -1.366247} 48614 {id 48614 c {1335.437698 309.322675} p {{1311.624146 297.276917} {1319.497681 333.455688} {1359.369629 321.428314} {1351.731812 284.653564}} size 37 angle -1.356509} 48617 {id 48617 c {1243.749759 262.137148} p {{1221.931274 250.747498} {1228.881592 285.992737} {1265.767822 273.630981} {1258.832153 237.937836}} size 35 angle -1.376096} 48619 {id 48619 c {1272.913442 404.925019} p {{1250.692993 392.101196} {1257.740112 428.166321} {1295.694092 418.072144} {1288.293701 381.366760}} size 36 angle -1.377828} 48600 {id 48600 c {1564.066360 65.587149} p {{1535.401978 54.913307} {1544.859375 94.562202} {1593.631592 76.596443} {1583.183472 36.747677}} size 40 angle -1.336643} 48602 {id 48602 c {1603.038917 226.582457} p {{1572.679565 213.412918} {1582.847534 254.925323} {1633.826782 239.937881} {1623.557983 197.779617}} size 42 angle -1.330587} 48605 {id 48605 c {1488.559622 178.892756} p {{1469.938721 206.515533} {1516.978638 191.118256} {1507.937988 150.146332} {1460.885254 166.987595}} size 49 angle 0.316332} 48607 {id 48607 c {1526.241290 334.702058} p {{1498.980103 321.365814} {1506.401367 362.501465} {1555.100708 348.820160} {1545.040161 308.361359}} size 41 angle -1.392307} 48608 {id 48608 c {1384.624545 133.919279} p {{1359.451660 122.670517} {1367.424805 161.219101} {1410.523193 145.492355} {1401.587036 106.996025}} size 39 angle -1.366839} 48610 {id 48610 c {1417.455410 284.507754} p {{1391.823120 272.121887} {1400.070435 310.095215} {1443.510010 297.097687} {1435.313721 258.223633}} size 38 angle -1.356931} 48613 {id 48613 c {1319.617852 236.336932} p {{1303.319336 261.778351} {1343.896973 248.560242} {1336.254272 210.368057} {1295.936890 224.414764}} size 42 angle 0.314909} 48615 {id 48615 c {1350.581998 384.136254} p {{1326.474976 370.715607} {1334.264893 408.357025} {1375.247803 397.867981} {1367.291260 359.333374}} size 38 angle -1.366726} 48616 {id 48616 c {1229.578846 191.805533} p {{1207.622070 180.703964} {1214.551758 216.823944} {1252.010010 203.146957} {1244.745361 166.554993}} size 36 angle -1.381248} 48618 {id 48618 c {1258.106145 333.438437} p {{1236.033203 321.214142} {1243.164917 356.981049} {1280.836792 346.026978} {1273.311035 309.480377}} size 36 angle -1.373983}} imageName pose-1781543257841-14.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg}}} {point {862.566467 507.444885} det {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221} width 1920 points {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} id 48618 posesReport {
<p>Poses:</p><ol>
<li style="padding-bottom: 1em">
RMSE 0.725728225238
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-0.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1367.43,391.922 1405.21,389.763 1402.77,354.724 1364.97,357.133 1367.43,391.922" fill="none" stroke="green" stroke-width="3" />
<text x="1367.431885" y="391.921936" fill="green" font-size="12">48601</text>
<polyline points="1520.25,382.996 1560.27,380.483 1556.39,345.479 1516.82,348.073 1520.25,382.996" fill="none" stroke="green" stroke-width="3" />
<text x="1520.251709" y="382.996368" fill="green" font-size="12">48603</text>
<polyline points="1296.98,465.833 1334.82,464.71 1332.75,428.698 1294.88,430.397 1296.98,465.833" fill="none" stroke="green" stroke-width="3" />
<text x="1296.983887" y="465.832520" fill="green" font-size="12">48604</text>
<polyline points="1448.43,459.266 1487.84,457.079 1484.45,420.929 1445.62,422.948 1448.43,459.266" fill="none" stroke="green" stroke-width="3" />
<text x="1448.426758" y="459.265656" fill="green" font-size="12">48606</text>
<polyline points="1377.01,533.713 1415.9,532.741 1413.31,495.927 1374.51,497.628 1377.01,533.713" fill="none" stroke="green" stroke-width="3" />
<text x="1377.006226" y="533.712585" fill="green" font-size="12">48609</text>
<polyline points="1533.44,527.498 1572.45,526.568 1569.05,489.148 1530.55,490.243 1533.44,527.498" fill="none" stroke="green" stroke-width="3" />
<text x="1533.442505" y="527.498169" fill="green" font-size="12">48611</text>
<polyline points="1306.24,608.615 1344.44,607.667 1341.83,571.074 1303.76,572.427 1306.24,608.615" fill="none" stroke="green" stroke-width="3" />
<text x="1306.240601" y="608.614990" fill="green" font-size="12">48612</text>
<polyline points="1460.86,603.967 1500.82,602.854 1497.58,565.594 1457.4,567.252 1460.86,603.967" fill="none" stroke="green" stroke-width="3" />
<text x="1460.857666" y="603.967041" fill="green" font-size="12">48614</text>
<polyline points="1388.15,680.365 1427.64,679.63 1424.39,642.253 1385.15,643.142 1388.15,680.365" fill="none" stroke="green" stroke-width="3" />
<text x="1388.146118" y="680.364746" fill="green" font-size="12">48617</text>
<polyline points="1547.08,676.827 1587.98,675.831 1583.96,637.826 1543.5,639.095 1547.08,676.827" fill="none" stroke="green" stroke-width="3" />
<text x="1547.084473" y="676.826904" fill="green" font-size="12">48619</text>
<polyline points="1293.4,397.174 1331.19,394.613 1328.71,359.331 1291.37,362.216 1293.4,397.174" fill="none" stroke="green" stroke-width="3" />
<text x="1293.403809" y="397.174408" fill="green" font-size="12">48600</text>
<polyline points="1443.13,388.179 1482.12,386.911 1479.02,350.824 1440.81,353.366 1443.13,388.179" fill="none" stroke="green" stroke-width="3" />
<text x="1443.130371" y="388.178741" fill="green" font-size="12">48602</text>
<polyline points="1372.4,463.839 1411.64,461.251 1408.59,425.34 1369.88,427.32 1372.4,463.839" fill="none" stroke="green" stroke-width="3" />
<text x="1372.398560" y="463.838928" fill="green" font-size="12">48605</text>
<polyline points="1526.84,455.811 1566.59,454.317 1563.77,416.481 1523.53,419.376 1526.84,455.811" fill="none" stroke="green" stroke-width="3" />
<text x="1526.837891" y="455.811432" fill="green" font-size="12">48607</text>
<polyline points="1302.11,537.349 1340.64,535.987 1338.15,499.382 1299.49,500.602 1302.11,537.349" fill="none" stroke="green" stroke-width="3" />
<text x="1302.109009" y="537.349243" fill="green" font-size="12">48608</text>
<polyline points="1454.54,531.718 1494.85,530.375 1491.63,493.079 1451.51,495.199 1454.54,531.718" fill="none" stroke="green" stroke-width="3" />
<text x="1454.544067" y="531.717834" fill="green" font-size="12">48610</text>
<polyline points="1383.69,606.713 1422.48,605.906 1419.35,568.597 1380.47,569.625 1383.69,606.713" fill="none" stroke="green" stroke-width="3" />
<text x="1383.686401" y="606.712585" fill="green" font-size="12">48613</text>
<polyline points="1540.74,601.987 1580.55,600.764 1576.89,563.217 1537.03,564.14 1540.74,601.987" fill="none" stroke="green" stroke-width="3" />
<text x="1540.743286" y="601.986816" fill="green" font-size="12">48615</text>
<polyline points="1311.35,682.408 1350.5,681.46 1347.78,643.882 1309.22,645.006 1311.35,682.408" fill="none" stroke="green" stroke-width="3" />
<text x="1311.354126" y="682.407532" fill="green" font-size="12">48616</text>
<polyline points="1467.18,679.633 1507.81,677.993 1504.76,640.16 1464.39,641.373 1467.18,679.633" fill="none" stroke="green" stroke-width="3" />
<text x="1467.177856" y="679.632935" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.89131853376
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-1.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1377.59,233.64 1417.54,229.659 1414.2,192.218 1374.62,196.259 1377.59,233.64" fill="none" stroke="green" stroke-width="3" />
<text x="1377.588257" y="233.639587" fill="green" font-size="12">48601</text>
<polyline points="1535.31,218.149 1575.98,214.535 1571.93,177.086 1531.56,180.869 1535.31,218.149" fill="none" stroke="green" stroke-width="3" />
<text x="1535.305908" y="218.149307" fill="green" font-size="12">48603</text>
<polyline points="1306.12,313.841 1345.08,310.326 1341.59,274.213 1303.34,277.205 1306.12,313.841" fill="none" stroke="green" stroke-width="3" />
<text x="1306.116943" y="313.840912" fill="green" font-size="12">48604</text>
<polyline points="1462.41,299.948 1502.63,296.395 1499.19,258.895 1459.29,262.52 1462.41,299.948" fill="none" stroke="green" stroke-width="3" />
<text x="1462.405518" y="299.948456" fill="green" font-size="12">48606</text>
<polyline points="1390.1,380.932 1429.53,377.934 1426.24,340.646 1386.85,344.056 1390.1,380.932" fill="none" stroke="green" stroke-width="3" />
<text x="1390.102661" y="380.931671" fill="green" font-size="12">48609</text>
<polyline points="1549.18,367.838 1588.58,365.236 1584.65,327.663 1546.49,329.953 1549.18,367.838" fill="none" stroke="green" stroke-width="3" />
<text x="1549.179443" y="367.838379" fill="green" font-size="12">48611</text>
<polyline points="1318.51,462.043 1358.46,459.202 1354.72,421.314 1315.22,424.358 1318.51,462.043" fill="none" stroke="green" stroke-width="3" />
<text x="1318.508179" y="462.043243" fill="green" font-size="12">48612</text>
<polyline points="1476.8,449.947 1516.71,447.297 1512.82,409.048 1472.77,412.225 1476.8,449.947" fill="none" stroke="green" stroke-width="3" />
<text x="1476.802612" y="449.946777" fill="green" font-size="12">48614</text>
<polyline points="1404.71,531.414 1445.43,528.575 1441.9,490.051 1400.94,492.917 1404.71,531.414" fill="none" stroke="green" stroke-width="3" />
<text x="1404.714844" y="531.413879" fill="green" font-size="12">48617</text>
<polyline points="1566.05,520.226 1606.48,517.6 1601.71,478.767 1560.93,481.633 1566.05,520.226" fill="none" stroke="green" stroke-width="3" />
<text x="1566.048706" y="520.226074" fill="green" font-size="12">48619</text>
<polyline points="1299.98,243.184 1339.74,239.226 1336.86,201.814 1296.94,205.821 1299.98,243.184" fill="none" stroke="green" stroke-width="3" />
<text x="1299.982056" y="243.184250" fill="green" font-size="12">48600</text>
<polyline points="1456.19,227.932 1496.75,224.579 1493.37,186.521 1452.81,190.511 1456.19,227.932" fill="none" stroke="green" stroke-width="3" />
<text x="1456.190552" y="227.932159" fill="green" font-size="12">48602</text>
<polyline points="1381.08,272.196 1383.98,309.481 1423.91,305.67 1420.3,268.409 1381.08,272.196" fill="none" stroke="green" stroke-width="3" />
<text x="1381.081299" y="272.196045" fill="green" font-size="12">48605</text>
<polyline points="1542.88,294.537 1582.19,292.009 1578.75,254.058 1539.62,256.704 1542.88,294.537" fill="none" stroke="green" stroke-width="3" />
<text x="1542.879883" y="294.537292" fill="green" font-size="12">48607</text>
<polyline points="1312.41,390.445 1352.47,386.979 1349.09,349.085 1309.4,353.059 1312.41,390.445" fill="none" stroke="green" stroke-width="3" />
<text x="1312.406006" y="390.445038" fill="green" font-size="12">48608</text>
<polyline points="1469.6,377.691 1510.82,373.957 1506.69,336.139 1466.97,339.796 1469.6,377.691" fill="none" stroke="green" stroke-width="3" />
<text x="1469.599854" y="377.690796" fill="green" font-size="12">48610</text>
<polyline points="1394.12,420.463 1397.87,459 1438.66,455.776 1434.26,417.358 1394.12,420.463" fill="none" stroke="green" stroke-width="3" />
<text x="1394.115112" y="420.463196" fill="green" font-size="12">48613</text>
<polyline points="1557.11,447.186 1598.87,444.504 1594.43,405.246 1553.89,408.197 1557.11,447.186" fill="none" stroke="green" stroke-width="3" />
<text x="1557.106689" y="447.186432" fill="green" font-size="12">48615</text>
<polyline points="1325.91,539.723 1366.12,537.195 1362.37,498.437 1322.23,501.476 1325.91,539.723" fill="none" stroke="green" stroke-width="3" />
<text x="1325.910889" y="539.723450" fill="green" font-size="12">48616</text>
<polyline points="1485.65,528.902 1527.6,526.066 1523.4,486.462 1481.83,489.707 1485.65,528.902" fill="none" stroke="green" stroke-width="3" />
<text x="1485.648682" y="528.901550" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.12427806234
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-2.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1480.65,85.9842 1536.13,82.8197 1538.86,22.7911 1483.49,26.2682 1480.65,85.9842" fill="none" stroke="green" stroke-width="3" />
<text x="1480.648926" y="85.984230" fill="green" font-size="12">48601</text>
<polyline points="1365.31,209.826 1421.08,206.09 1423,147.409 1367.77,150.873 1365.31,209.826" fill="none" stroke="green" stroke-width="3" />
<text x="1365.312988" y="209.825806" fill="green" font-size="12">48604</text>
<polyline points="1581.29,195.975 1636.13,193.27 1640.51,134.807 1585.92,137.737 1581.29,195.975" fill="none" stroke="green" stroke-width="3" />
<text x="1581.291260" y="195.974930" fill="green" font-size="12">48606</text>
<polyline points="1467.73,311.926 1520.55,308.732 1524.37,254.145 1470.83,257.484 1467.73,311.926" fill="none" stroke="green" stroke-width="3" />
<text x="1467.725464" y="311.925690" fill="green" font-size="12">48609</text>
<polyline points="1678.11,299.656 1728.07,296.963 1733.85,242.453 1684.11,245.028 1678.11,299.656" fill="none" stroke="green" stroke-width="3" />
<text x="1678.112183" y="299.655853" fill="green" font-size="12">48611</text>
<polyline points="1358.84,424.565 1411.06,421.179 1412.72,368.966 1360.27,372.199 1358.84,424.565" fill="none" stroke="green" stroke-width="3" />
<text x="1358.841064" y="424.564758" fill="green" font-size="12">48612</text>
<polyline points="1565.01,411.651 1615.94,408.256 1620.92,355.985 1568.79,358.936 1565.01,411.651" fill="none" stroke="green" stroke-width="3" />
<text x="1565.013916" y="411.650513" fill="green" font-size="12">48614</text>
<polyline points="1456.93,518.885 1508.52,515.552 1511.41,465.146 1459.29,468.313 1456.93,518.885" fill="none" stroke="green" stroke-width="3" />
<text x="1456.933105" y="518.884766" fill="green" font-size="12">48617</text>
<polyline points="1656.81,506.011 1707.05,503.156 1711.7,452.871 1661.05,455.896 1656.81,506.011" fill="none" stroke="green" stroke-width="3" />
<text x="1656.806152" y="506.011230" fill="green" font-size="12">48619</text>
<polyline points="1369.52,92.6488 1426.72,87.9975 1428.33,28.0723 1372.39,30.325 1369.52,92.6488" fill="none" stroke="green" stroke-width="3" />
<text x="1369.518433" y="92.648804" fill="green" font-size="12">48600</text>
<polyline points="1590.64,78.1485 1645.18,75.5008 1650.33,15.4836 1595.3,17.8232 1590.64,78.1485" fill="none" stroke="green" stroke-width="3" />
<text x="1590.636230" y="78.148476" fill="green" font-size="12">48602</text>
<polyline points="1473.29,202.666 1529.04,199.092 1532.44,140.083 1476.36,142.849 1473.29,202.666" fill="none" stroke="green" stroke-width="3" />
<text x="1473.294922" y="202.666061" fill="green" font-size="12">48605</text>
<polyline points="1687.9,188.728 1740.14,186.814 1747.22,127.192 1692.82,129.918 1687.9,188.728" fill="none" stroke="green" stroke-width="3" />
<text x="1687.903442" y="188.728394" fill="green" font-size="12">48607</text>
<polyline points="1361.93,318.369 1415.51,314.445 1418.56,259.148 1363.44,263.838 1361.93,318.369" fill="none" stroke="green" stroke-width="3" />
<text x="1361.929688" y="318.369263" fill="green" font-size="12">48608</text>
<polyline points="1572.5,305.586 1625.16,301.928 1630.32,247.095 1577.11,250.361 1572.5,305.586" fill="none" stroke="green" stroke-width="3" />
<text x="1572.501587" y="305.586060" fill="green" font-size="12">48610</text>
<polyline points="1462.31,417.067 1514.5,414.531 1517.47,361.646 1465.07,364.23 1462.31,417.067" fill="none" stroke="green" stroke-width="3" />
<text x="1462.307617" y="417.067352" fill="green" font-size="12">48613</text>
<polyline points="1666.8,404.402 1716.85,401.537 1721.93,349.596 1672.44,351.307 1666.8,404.402" fill="none" stroke="green" stroke-width="3" />
<text x="1666.799194" y="404.401581" fill="green" font-size="12">48615</text>
<polyline points="1355.68,523.805 1407.25,521.064 1409.44,470.152 1356.13,473.535 1355.68,523.805" fill="none" stroke="green" stroke-width="3" />
<text x="1355.683105" y="523.804565" fill="green" font-size="12">48616</text>
<polyline points="1557.03,511.571 1609.12,507.885 1612.78,457.055 1561.36,460.423 1557.03,511.571" fill="none" stroke="green" stroke-width="3" />
<text x="1557.027588" y="511.571320" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.96923416025
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-3.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1222.11,348.785 1216.37,300.245 1166.46,306.593 1172.06,355.129 1222.11,348.785" fill="none" stroke="green" stroke-width="3" />
<text x="1222.111084" y="348.784912" fill="green" font-size="12">48601</text>
<polyline points="1199.85,158.204 1193.67,110.035 1144,116.397 1149.26,164.909 1199.85,158.204" fill="none" stroke="green" stroke-width="3" />
<text x="1199.847046" y="158.204208" fill="green" font-size="12">48603</text>
<polyline points="1338.62,434.53 1331.86,384.154 1279.36,390.333 1285.77,440.204 1338.62,434.53" fill="none" stroke="green" stroke-width="3" />
<text x="1338.622192" y="434.530487" fill="green" font-size="12">48604</text>
<polyline points="1311.47,240.157 1305.32,190.902 1253.95,197.879 1260.24,246.411 1311.47,240.157" fill="none" stroke="green" stroke-width="3" />
<text x="1311.468262" y="240.157288" fill="green" font-size="12">48606</text>
<polyline points="1428.08,322.549 1420.25,274.269 1368.6,281.004 1375.68,328.877 1428.08,322.549" fill="none" stroke="green" stroke-width="3" />
<text x="1428.077271" y="322.549194" fill="green" font-size="12">48609</text>
<polyline points="1399.74,131.376 1391.64,85.3372 1341.11,91.8847 1348.33,138.087 1399.74,131.376" fill="none" stroke="green" stroke-width="3" />
<text x="1399.739502" y="131.376297" fill="green" font-size="12">48611</text>
<polyline points="1550.77,409.181 1541.71,358.775 1489.09,365.109 1495.86,415.912 1550.77,409.181" fill="none" stroke="green" stroke-width="3" />
<text x="1550.766846" y="409.180939" fill="green" font-size="12">48612</text>
<polyline points="1517.27,213.761 1508.71,165.099 1456.42,171.521 1463.94,220.6 1517.27,213.761" fill="none" stroke="green" stroke-width="3" />
<text x="1517.266602" y="213.760712" fill="green" font-size="12">48614</text>
<polyline points="1639.27,297.008 1629.77,248.022 1577.12,254.516 1586.11,303.228 1639.27,297.008" fill="none" stroke="green" stroke-width="3" />
<text x="1639.266846" y="297.007874" fill="green" font-size="12">48617</text>
<polyline points="1602.3,106.652 1592.92,59.6051 1542.63,65.8528 1550.4,112.725 1602.3,106.652" fill="none" stroke="green" stroke-width="3" />
<text x="1602.301147" y="106.652153" fill="green" font-size="12">48619</text>
<polyline points="1236.49,449.318 1229.8,398.073 1177.8,404.405 1183.69,455.228 1236.49,449.318" fill="none" stroke="green" stroke-width="3" />
<text x="1236.492432" y="449.318146" fill="green" font-size="12">48600</text>
<polyline points="1212.46,253.816 1207.14,204.864 1155.54,211.796 1161.42,260.15 1212.46,253.816" fill="none" stroke="green" stroke-width="3" />
<text x="1212.459473" y="253.815598" fill="green" font-size="12">48602</text>
<polyline points="1325.86,337.833 1318.71,289.046 1267.29,295.762 1274.16,344.212 1325.86,337.833" fill="none" stroke="green" stroke-width="3" />
<text x="1325.864990" y="337.833160" fill="green" font-size="12">48605</text>
<polyline points="1301.37,146.699 1294.98,99.184 1244.21,105.125 1249.89,152.637 1301.37,146.699" fill="none" stroke="green" stroke-width="3" />
<text x="1301.373169" y="146.699203" fill="green" font-size="12">48607</text>
<polyline points="1445.37,424.986 1437.86,373.319 1384.36,379.553 1391.05,431.454 1445.37,424.986" fill="none" stroke="green" stroke-width="3" />
<text x="1445.368042" y="424.986145" fill="green" font-size="12">48608</text>
<polyline points="1415.36,229.485 1408.3,180.035 1355.68,186.583 1362.75,235.348 1415.36,229.485" fill="none" stroke="green" stroke-width="3" />
<text x="1415.355225" y="229.484650" fill="green" font-size="12">48610</text>
<polyline points="1535.19,311.401 1525.94,263.202 1472.87,269.811 1482.18,317.866 1535.19,311.401" fill="none" stroke="green" stroke-width="3" />
<text x="1535.192505" y="311.400970" fill="green" font-size="12">48613</text>
<polyline points="1503.44,121.381 1494.25,74.7291 1443.12,81.2754 1450.7,127.522 1503.44,121.381" fill="none" stroke="green" stroke-width="3" />
<text x="1503.442139" y="121.380783" fill="green" font-size="12">48615</text>
<polyline points="1659.89,399.384 1649.84,348.796 1596,354.982 1604.8,406.215 1659.89,399.384" fill="none" stroke="green" stroke-width="3" />
<text x="1659.892212" y="399.384186" fill="green" font-size="12">48616</text>
<polyline points="1622.02,204.145 1613.07,154.467 1560.33,160.729 1568.57,210.357 1622.02,204.145" fill="none" stroke="green" stroke-width="3" />
<text x="1622.018433" y="204.144791" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.60197092768
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-4.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1161.82,600.762 1163.24,562.024 1120.93,563.719 1120.48,602.199 1161.82,600.762" fill="none" stroke="green" stroke-width="3" />
<text x="1161.815552" y="600.761658" fill="green" font-size="12">48601</text>
<polyline points="1167.4,439.41 1168.94,395.168 1123.94,397.177 1122.79,441.483 1167.4,439.41" fill="none" stroke="green" stroke-width="3" />
<text x="1167.404541" y="439.410339" fill="green" font-size="12">48603</text>
<polyline points="1241.05,672.531 1243.32,635.811 1201.96,636.943 1200.22,673.816 1241.05,672.531" fill="none" stroke="green" stroke-width="3" />
<text x="1241.052490" y="672.530945" fill="green" font-size="12">48604</text>
<polyline points="1250.24,519.469 1253.13,477.784 1208.7,479.424 1206.81,521.516 1250.24,519.469" fill="none" stroke="green" stroke-width="3" />
<text x="1250.237061" y="519.468994" fill="green" font-size="12">48606</text>
<polyline points="1329.27,595.172 1332.63,555.745 1289.95,557.359 1286.86,596.405 1329.27,595.172" fill="none" stroke="green" stroke-width="3" />
<text x="1329.272949" y="595.172302" fill="green" font-size="12">48609</text>
<polyline points="1345.42,431.92 1348.67,386.653 1303.43,388.489 1300.43,433.823 1345.42,431.92" fill="none" stroke="green" stroke-width="3" />
<text x="1345.424316" y="431.919800" fill="green" font-size="12">48611</text>
<polyline points="1405.2,668.071 1409.6,630.439 1367.86,631.949 1363.37,668.476 1405.2,668.071" fill="none" stroke="green" stroke-width="3" />
<text x="1405.200684" y="668.071045" fill="green" font-size="12">48612</text>
<polyline points="1424.6,512.735 1429.51,470.11 1384.81,472.208 1379.89,514.238 1424.6,512.735" fill="none" stroke="green" stroke-width="3" />
<text x="1424.596436" y="512.734863" fill="green" font-size="12">48614</text>
<polyline points="1500.18,589.614 1506.08,549.731 1462.4,551.368 1457.02,590.926 1500.18,589.614" fill="none" stroke="green" stroke-width="3" />
<text x="1500.176636" y="589.614075" fill="green" font-size="12">48617</text>
<polyline points="1525.06,423.736 1531.93,378.371 1485.98,380.417 1479.56,425.79 1525.06,423.736" fill="none" stroke="green" stroke-width="3" />
<text x="1525.058838" y="423.735840" fill="green" font-size="12">48619</text>
<polyline points="1157.73,676.412 1159.24,639.123 1118.03,639.842 1117.27,677.301 1157.73,676.412" fill="none" stroke="green" stroke-width="3" />
<text x="1157.728149" y="676.412109" fill="green" font-size="12">48600</text>
<polyline points="1163.27,522.951 1164.35,480.564 1119.99,481.755 1119.64,524.188 1163.27,522.951" fill="none" stroke="green" stroke-width="3" />
<text x="1163.265625" y="522.951355" fill="green" font-size="12">48602</text>
<polyline points="1201.27,599.938 1243.42,599.076 1245.84,560.111 1203.13,561.096 1201.27,599.938" fill="none" stroke="green" stroke-width="3" />
<text x="1201.270752" y="599.937561" fill="green" font-size="12">48605</text>
<polyline points="1254.38,435.44 1256.47,390.93 1211.25,392.006 1208.93,436.124 1254.38,435.44" fill="none" stroke="green" stroke-width="3" />
<text x="1254.376343" y="435.440247" fill="green" font-size="12">48607</text>
<polyline points="1320.73,671.877 1324.38,634.33 1282.55,635.446 1278.99,673.79 1320.73,671.877" fill="none" stroke="green" stroke-width="3" />
<text x="1320.725586" y="671.876770" fill="green" font-size="12">48608</text>
<polyline points="1335.12,517.578 1339.2,475.335 1294.03,476.139 1290.77,518.369 1335.12,517.578" fill="none" stroke="green" stroke-width="3" />
<text x="1335.116821" y="517.577820" fill="green" font-size="12">48610</text>
<polyline points="1369.9,595.453 1413.16,593.947 1417.28,554.43 1373.91,555.237 1369.9,595.453" fill="none" stroke="green" stroke-width="3" />
<text x="1369.902954" y="595.453003" fill="green" font-size="12">48613</text>
<polyline points="1433.58,429.079 1438.58,383.783 1391.77,385.845 1387.74,430.044 1433.58,429.079" fill="none" stroke="green" stroke-width="3" />
<text x="1433.579224" y="429.078918" fill="green" font-size="12">48615</text>
<polyline points="1487.4,667.221 1492.82,629.765 1450.28,631.479 1444.67,668.2 1487.4,667.221" fill="none" stroke="green" stroke-width="3" />
<text x="1487.397583" y="667.221069" fill="green" font-size="12">48616</text>
<polyline points="1510.94,511.321 1517.89,468.175 1472.14,469.854 1465.75,512.261 1510.94,511.321" fill="none" stroke="green" stroke-width="3" />
<text x="1510.942993" y="511.321289" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.01227215325
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-5.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="961.526,180.89 998.663,173.187 994.492,137.17 957.514,145.294 961.526,180.89" fill="none" stroke="green" stroke-width="3" />
<text x="961.526062" y="180.890030" fill="green" font-size="12">48601</text>
<polyline points="1111.38,149.231 1150.94,141.91 1145.98,104.73 1106.94,113.302 1111.38,149.231" fill="none" stroke="green" stroke-width="3" />
<text x="1111.380981" y="149.230835" fill="green" font-size="12">48603</text>
<polyline points="897.504,265.618 933.629,258.776 929.834,223.057 893.547,230.007 897.504,265.618" fill="none" stroke="green" stroke-width="3" />
<text x="897.504028" y="265.617676" fill="green" font-size="12">48604</text>
<polyline points="1044.22,237.68 1082.99,230.329 1078.23,193.237 1039.66,200.734 1044.22,237.68" fill="none" stroke="green" stroke-width="3" />
<text x="1044.215210" y="237.679565" fill="green" font-size="12">48606</text>
<polyline points="978.373,323.581 1015.69,317.462 1011.31,280.87 973.993,287.962 978.373,323.581" fill="none" stroke="green" stroke-width="3" />
<text x="978.372559" y="323.581116" fill="green" font-size="12">48609</text>
<polyline points="1130.85,296.856 1170.36,290.62 1165.28,253.041 1125.9,259.465 1130.85,296.856" fill="none" stroke="green" stroke-width="3" />
<text x="1130.848511" y="296.855865" fill="green" font-size="12">48611</text>
<polyline points="912.622,409.819 949.752,403.973 945.61,366.796 909.083,373.39 912.622,409.819" fill="none" stroke="green" stroke-width="3" />
<text x="912.621643" y="409.819275" fill="green" font-size="12">48612</text>
<polyline points="1062.53,385.34 1101.74,378.891 1096.73,341.298 1058.06,348.126 1062.53,385.34" fill="none" stroke="green" stroke-width="3" />
<text x="1062.534424" y="385.340088" fill="green" font-size="12">48614</text>
<polyline points="994.766,472.561 1033.85,466.87 1029.12,428.338 990.725,434.344 994.766,472.561" fill="none" stroke="green" stroke-width="3" />
<text x="994.765564" y="472.561249" fill="green" font-size="12">48617</text>
<polyline points="1150.67,449.554 1191.84,443.556 1186.21,404.371 1145.66,410.473 1150.67,449.554" fill="none" stroke="green" stroke-width="3" />
<text x="1150.667725" y="449.554413" fill="green" font-size="12">48619</text>
<polyline points="889.985,199.787 926.488,191.674 922.555,156.222 886.374,163.982 889.985,199.787" fill="none" stroke="green" stroke-width="3" />
<text x="889.984741" y="199.787430" fill="green" font-size="12">48600</text>
<polyline points="1034.97,168.698 1073.74,160.712 1068.65,124.181 1030.37,132.357 1034.97,168.698" fill="none" stroke="green" stroke-width="3" />
<text x="1034.971924" y="168.697723" fill="green" font-size="12">48602</text>
<polyline points="1007.71,248.093 1003.32,211.708 965.542,219.252 970.112,255.544 1007.71,248.093" fill="none" stroke="green" stroke-width="3" />
<text x="1007.705933" y="248.093491" fill="green" font-size="12">48605</text>
<polyline points="1120.36,225.086 1160.32,218.317 1155.17,180.507 1115.31,187.178 1120.36,225.086" fill="none" stroke="green" stroke-width="3" />
<text x="1120.361816" y="225.086212" fill="green" font-size="12">48607</text>
<polyline points="906.624,340.189 942.87,333.021 938.392,297.048 902.169,304.013 906.624,340.189" fill="none" stroke="green" stroke-width="3" />
<text x="906.624146" y="340.189362" fill="green" font-size="12">48608</text>
<polyline points="1053.66,313.242 1092.29,306.299 1087.53,269.16 1048.9,276.496 1053.66,313.242" fill="none" stroke="green" stroke-width="3" />
<text x="1053.658569" y="313.241547" fill="green" font-size="12">48610</text>
<polyline points="1026.17,393.921 1021.38,356.461 983.373,362.746 987.669,399.949 1026.17,393.921" fill="none" stroke="green" stroke-width="3" />
<text x="1026.171143" y="393.921082" fill="green" font-size="12">48613</text>
<polyline points="1141.12,373.867 1181.45,367.684 1175.56,329.788 1136.04,335.906 1141.12,373.867" fill="none" stroke="green" stroke-width="3" />
<text x="1141.118408" y="373.867371" fill="green" font-size="12">48615</text>
<polyline points="922.38,485.614 960.985,480.247 955.976,441.965 918.181,447.772 922.38,485.614" fill="none" stroke="green" stroke-width="3" />
<text x="922.379578" y="485.613617" fill="green" font-size="12">48616</text>
<polyline points="1073,463.024 1113.5,456.693 1107.94,417.233 1068.06,423.802 1073,463.024" fill="none" stroke="green" stroke-width="3" />
<text x="1073.001709" y="463.023590" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.0423236365
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-6.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="973.478,90.7454 1019.58,88.3579 1018.22,35.5119 971.393,38.0315 973.478,90.7454" fill="none" stroke="green" stroke-width="3" />
<text x="973.477661" y="90.745377" fill="green" font-size="12">48601</text>
<polyline points="1156.18,80.3913 1202.45,77.7942 1204.51,25.9644 1158.14,27.9488 1156.18,80.3913" fill="none" stroke="green" stroke-width="3" />
<text x="1156.181641" y="80.391281" fill="green" font-size="12">48603</text>
<polyline points="889.397,195.436 934.235,192.825 931.088,143.462 885.473,146.002 889.397,195.436" fill="none" stroke="green" stroke-width="3" />
<text x="889.396729" y="195.435806" fill="green" font-size="12">48604</text>
<polyline points="1065.12,184.975 1109.74,182.464 1110.23,133.209 1065.1,135.902 1065.12,184.975" fill="none" stroke="green" stroke-width="3" />
<text x="1065.120605" y="184.974594" fill="green" font-size="12">48606</text>
<polyline points="981.455,281.021 1023.61,278.444 1022.98,233.625 979.548,236.218 981.455,281.021" fill="none" stroke="green" stroke-width="3" />
<text x="981.454956" y="281.020996" fill="green" font-size="12">48609</text>
<polyline points="1150.32,270.641 1191.79,267.688 1194.59,222.833 1151.83,226.033 1150.32,270.641" fill="none" stroke="green" stroke-width="3" />
<text x="1150.322266" y="270.640564" fill="green" font-size="12">48611</text>
<polyline points="903.591,370.807 944.803,368.034 941.782,326.576 900.361,329.095 903.591,370.807" fill="none" stroke="green" stroke-width="3" />
<text x="903.591309" y="370.806976" fill="green" font-size="12">48612</text>
<polyline points="1066.02,360.52 1107.08,357.742 1107.17,316.263 1066.42,318.74 1066.02,360.52" fill="none" stroke="green" stroke-width="3" />
<text x="1066.020996" y="360.519623" fill="green" font-size="12">48614</text>
<polyline points="987.993,444.139 1027.96,441.847 1026.91,402.713 987.215,405.585 987.993,444.139" fill="none" stroke="green" stroke-width="3" />
<text x="987.993103" y="444.138885" fill="green" font-size="12">48617</text>
<polyline points="1144.6,433.874 1183.83,430.97 1185.66,391.943 1146.12,394.862 1144.6,433.874" fill="none" stroke="green" stroke-width="3" />
<text x="1144.602783" y="433.873840" fill="green" font-size="12">48619</text>
<polyline points="879.565,98.8311 926.215,95.174 922.728,41.9485 875.174,44.9588 879.565,98.8311" fill="none" stroke="green" stroke-width="3" />
<text x="879.565063" y="98.831100" fill="green" font-size="12">48600</text>
<polyline points="1062.45,87.6651 1108.79,85.0553 1109.04,31.7388 1062.93,34.4441 1062.45,87.6651" fill="none" stroke="green" stroke-width="3" />
<text x="1062.445923" y="87.665062" fill="green" font-size="12">48602</text>
<polyline points="973.271,143.106 975.749,192.658 1021.54,190.782 1018.92,140.877 973.271,143.106" fill="none" stroke="green" stroke-width="3" />
<text x="973.270996" y="143.105530" fill="green" font-size="12">48605</text>
<polyline points="1150.81,180.724 1195.43,177.985 1197.8,127.599 1151.8,131.887 1150.81,180.724" fill="none" stroke="green" stroke-width="3" />
<text x="1150.805542" y="180.724335" fill="green" font-size="12">48607</text>
<polyline points="895.314,289.226 938.358,286.46 935.249,240.887 891.718,243.977 895.314,289.226" fill="none" stroke="green" stroke-width="3" />
<text x="895.314270" y="289.225830" fill="green" font-size="12">48608</text>
<polyline points="1064.24,278.831 1106.52,275.831 1107.61,230.559 1063.49,233.553 1064.24,278.831" fill="none" stroke="green" stroke-width="3" />
<text x="1064.236572" y="278.830505" fill="green" font-size="12">48610</text>
<polyline points="982.016,326.395 984.393,368.503 1025.03,366.2 1023.77,323.807 982.016,326.395" fill="none" stroke="green" stroke-width="3" />
<text x="982.015869" y="326.394714" fill="green" font-size="12">48613</text>
<polyline points="1146.14,356.945 1186.64,354.646 1188.53,312.808 1147.28,314.565 1146.14,356.945" fill="none" stroke="green" stroke-width="3" />
<text x="1146.137329" y="356.945221" fill="green" font-size="12">48615</text>
<polyline points="908.726,452.526 949.157,450.607 946.694,410.507 905.706,413.912 908.726,452.526" fill="none" stroke="green" stroke-width="3" />
<text x="908.725525" y="452.526123" fill="green" font-size="12">48616</text>
<polyline points="1065.63,441.997 1105.94,439.001 1105.52,399.376 1065.62,402.341 1065.63,441.997" fill="none" stroke="green" stroke-width="3" />
<text x="1065.630981" y="441.996979" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.41663092406
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-7.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="930.949,336.128 970.724,329.257 967.532,303.302 928.905,310.056 930.949,336.128" fill="none" stroke="green" stroke-width="3" />
<text x="930.948975" y="336.128265" fill="green" font-size="12">48601</text>
<polyline points="1091.46,309.351 1132.33,302.97 1125.3,276.903 1085.33,283.652 1091.46,309.351" fill="none" stroke="green" stroke-width="3" />
<text x="1091.457397" y="309.351135" fill="green" font-size="12">48603</text>
<polyline points="853.659,405.51 894.607,398.498 893.468,369.617 852.656,376.193 853.659,405.51" fill="none" stroke="green" stroke-width="3" />
<text x="853.658752" y="405.510284" fill="green" font-size="12">48604</text>
<polyline points="1020.03,380.388 1062.75,374.629 1056.75,344.84 1015.53,351.817 1020.03,380.388" fill="none" stroke="green" stroke-width="3" />
<text x="1020.033813" y="380.388397" fill="green" font-size="12">48606</text>
<polyline points="941.885,454.018 986.398,446.855 982.146,415.507 938.896,422.11 941.885,454.018" fill="none" stroke="green" stroke-width="3" />
<text x="941.884705" y="454.018036" fill="green" font-size="12">48609</text>
<polyline points="1119.2,430.998 1164.85,424.474 1155.94,393.054 1111.96,398.352 1119.2,430.998" fill="none" stroke="green" stroke-width="3" />
<text x="1119.195923" y="430.997711" fill="green" font-size="12">48611</text>
<polyline points="855.905,537.082 902.737,530.845 900.828,494.607 855.529,502.06 855.905,537.082" fill="none" stroke="green" stroke-width="3" />
<text x="855.905457" y="537.082336" fill="green" font-size="12">48612</text>
<polyline points="1041.35,509.092 1089.7,502.621 1082.03,467.625 1035.66,473.14 1041.35,509.092" fill="none" stroke="green" stroke-width="3" />
<text x="1041.345215" y="509.091980" fill="green" font-size="12">48614</text>
<polyline points="955.284,598.862 1005.15,591.779 999.933,552.092 951.71,559.679 955.284,598.862" fill="none" stroke="green" stroke-width="3" />
<text x="955.283936" y="598.861938" fill="green" font-size="12">48617</text>
<polyline points="1155.16,570.688 1206.05,564.145 1194.97,525.254 1145.05,531.716 1155.16,570.688" fill="none" stroke="green" stroke-width="3" />
<text x="1155.157227" y="570.688110" fill="green" font-size="12">48619</text>
<polyline points="850.153,347.147 890.231,340.158 888.217,313.861 849.431,320.008 850.153,347.147" fill="none" stroke="green" stroke-width="3" />
<text x="850.153198" y="347.147217" fill="green" font-size="12">48600</text>
<polyline points="1009.68,321.059 1050.36,314.884 1045.06,288.546 1005.12,295.252 1009.68,321.059" fill="none" stroke="green" stroke-width="3" />
<text x="1009.680237" y="321.058594" fill="green" font-size="12">48602</text>
<polyline points="932.092,362.031 934.828,391.16 977.715,384.745 973.484,355.744 932.092,362.031" fill="none" stroke="green" stroke-width="3" />
<text x="932.091919" y="362.031342" fill="green" font-size="12">48605</text>
<polyline points="1103.99,365.027 1147.3,359.806 1139.06,329.696 1097.29,335.698 1103.99,365.027" fill="none" stroke="green" stroke-width="3" />
<text x="1103.990112" y="365.026520" fill="green" font-size="12">48607</text>
<polyline points="853.459,466.811 898.051,459.668 895.612,426.744 852.913,433.881 853.459,466.811" fill="none" stroke="green" stroke-width="3" />
<text x="853.459473" y="466.811462" fill="green" font-size="12">48608</text>
<polyline points="1029.29,440.778 1074.8,434.456 1068.16,402.347 1023.87,408.415 1029.29,440.778" fill="none" stroke="green" stroke-width="3" />
<text x="1029.286255" y="440.778168" fill="green" font-size="12">48610</text>
<polyline points="943.878,485.345 947.117,521.778 995.351,515.521 990.469,478.575 943.878,485.345" fill="none" stroke="green" stroke-width="3" />
<text x="943.878113" y="485.345337" fill="green" font-size="12">48613</text>
<polyline points="1135.34,495.411 1184.02,489.054 1173.78,453.439 1126.53,459.801 1135.34,495.411" fill="none" stroke="green" stroke-width="3" />
<text x="1135.341919" y="495.410980" fill="green" font-size="12">48615</text>
<polyline points="856.711,611.316 906.285,605.007 904.167,565.118 855.684,571.842 856.711,611.316" fill="none" stroke="green" stroke-width="3" />
<text x="856.710999" y="611.316040" fill="green" font-size="12">48616</text>
<polyline points="1054.05,584.49 1104.97,577.226 1096.61,537.481 1047.28,544.291 1054.05,584.49" fill="none" stroke="green" stroke-width="3" />
<text x="1054.046997" y="584.490234" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.7736504896
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-8.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="617.968,158.738 672.279,157.611 666.108,108.714 612.278,108.921 617.968,158.738" fill="none" stroke="green" stroke-width="3" />
<text x="617.967773" y="158.737991" fill="green" font-size="12">48601</text>
<polyline points="822.704,157.752 871.943,155.121 865.329,109.701 816.837,109.685 822.704,157.752" fill="none" stroke="green" stroke-width="3" />
<text x="822.703674" y="157.752472" fill="green" font-size="12">48603</text>
<polyline points="518.562,260.514 575.345,258.715 570.413,207.434 512.823,209.008 518.562,260.514" fill="none" stroke="green" stroke-width="3" />
<text x="518.562195" y="260.513550" fill="green" font-size="12">48604</text>
<polyline points="735.211,254.415 786.412,252.762 780.482,204.829 728.771,205.129 735.211,254.415" fill="none" stroke="green" stroke-width="3" />
<text x="735.210571" y="254.415009" fill="green" font-size="12">48606</text>
<polyline points="641.713,356.746 695.351,354.275 689.092,304.539 635.63,306.659 641.713,356.746" fill="none" stroke="green" stroke-width="3" />
<text x="641.712585" y="356.745972" fill="green" font-size="12">48609</text>
<polyline points="847.957,344.39 895.766,342.601 889.634,295.359 841.706,296.65 847.957,344.39" fill="none" stroke="green" stroke-width="3" />
<text x="847.957031" y="344.389862" fill="green" font-size="12">48611</text>
<polyline points="541.065,468.426 599.424,463.54 593.043,411.102 535.536,415.271 541.065,468.426" fill="none" stroke="green" stroke-width="3" />
<text x="541.064819" y="468.426208" fill="green" font-size="12">48612</text>
<polyline points="759.733,450.327 812.033,445.965 805.214,396.167 753.646,400.271 759.733,450.327" fill="none" stroke="green" stroke-width="3" />
<text x="759.732910" y="450.327362" fill="green" font-size="12">48614</text>
<polyline points="665.526,561.614 720.573,555.544 714.737,504.023 659.297,509.377 665.526,561.614" fill="none" stroke="green" stroke-width="3" />
<text x="665.525635" y="561.614380" fill="green" font-size="12">48617</text>
<polyline points="873.2,539.353 923.237,534.105 916.228,484.7 866.586,489.291 873.2,539.353" fill="none" stroke="green" stroke-width="3" />
<text x="873.199768" y="539.352783" fill="green" font-size="12">48619</text>
<polyline points="508.57,161.554 566.257,161.075 560.64,109.519 502.976,109.487 508.57,161.554" fill="none" stroke="green" stroke-width="3" />
<text x="508.569702" y="161.553513" fill="green" font-size="12">48600</text>
<polyline points="723.971,159.44 776.209,159.77 769.577,110.807 717.985,110.36 723.971,159.44" fill="none" stroke="green" stroke-width="3" />
<text x="723.971497" y="159.439575" fill="green" font-size="12">48602</text>
<polyline points="680.18,207.697 624.8,208.208 631.001,259.087 685.843,257.849 680.18,207.697" fill="none" stroke="green" stroke-width="3" />
<text x="680.179504" y="207.696640" fill="green" font-size="12">48605</text>
<polyline points="835.555,251.462 884.879,251.209 878.427,202.746 829.21,203.881 835.555,251.462" fill="none" stroke="green" stroke-width="3" />
<text x="835.554993" y="251.461700" fill="green" font-size="12">48607</text>
<polyline points="531.402,365.236 588.602,361.786 581.787,310.172 524.964,312.933 531.402,365.236" fill="none" stroke="green" stroke-width="3" />
<text x="531.402344" y="365.235870" fill="green" font-size="12">48608</text>
<polyline points="749.381,353.553 799.943,350.367 793.67,301.761 742.782,304.533 749.381,353.553" fill="none" stroke="green" stroke-width="3" />
<text x="749.380554" y="353.552917" fill="green" font-size="12">48610</text>
<polyline points="704.556,405.732 649.145,409.02 654.927,461.28 711.184,457.207 704.556,405.732" fill="none" stroke="green" stroke-width="3" />
<text x="704.556458" y="405.732422" fill="green" font-size="12">48613</text>
<polyline points="860.786,443.784 911.163,440.626 903.89,391.646 854.757,393.964 860.786,443.784" fill="none" stroke="green" stroke-width="3" />
<text x="860.786133" y="443.784180" fill="green" font-size="12">48615</text>
<polyline points="553.941,575.834 612.32,569.507 606.886,516.176 547.775,522.218 553.941,575.834" fill="none" stroke="green" stroke-width="3" />
<text x="553.940918" y="575.834351" fill="green" font-size="12">48616</text>
<polyline points="773.32,551.863 825.849,545.706 819.72,494.74 766.975,500.167 773.32,551.863" fill="none" stroke="green" stroke-width="3" />
<text x="773.319641" y="551.862793" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 3.33980752481
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-9.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="331.796,179.575 398.035,189.569 395.757,129.765 330.483,118.607 331.796,179.575" fill="none" stroke="green" stroke-width="3" />
<text x="331.795715" y="179.574631" fill="green" font-size="12">48601</text>
<polyline points="569.365,215.626 621.879,224.079 623.512,171.88 570.107,161.631 569.365,215.626" fill="none" stroke="green" stroke-width="3" />
<text x="569.365417" y="215.626068" fill="green" font-size="12">48603</text>
<polyline points="198.914,282.412 268.121,288.495 267.338,229.509 195.165,221.004 198.914,282.412" fill="none" stroke="green" stroke-width="3" />
<text x="198.913910" y="282.412262" fill="green" font-size="12">48604</text>
<polyline points="457.602,306.475 514.791,312.369 514.794,260.056 457.519,252.764 457.602,306.475" fill="none" stroke="green" stroke-width="3" />
<text x="457.602051" y="306.474640" fill="green" font-size="12">48606</text>
<polyline points="338.808,404.953 400.323,407.798 398.998,355.028 336.651,350.535 338.808,404.953" fill="none" stroke="green" stroke-width="3" />
<text x="338.807770" y="404.953491" fill="green" font-size="12">48609</text>
<polyline points="566.986,416.086 617.135,418.671 617.892,371.553 567.347,367.559 566.986,416.086" fill="none" stroke="green" stroke-width="3" />
<text x="566.986328" y="416.086365" fill="green" font-size="12">48611</text>
<polyline points="212.856,511.161 280.776,510.973 278.63,457.284 209.694,456.002 212.856,511.161" fill="none" stroke="green" stroke-width="3" />
<text x="212.855713" y="511.161255" fill="green" font-size="12">48612</text>
<polyline points="459.367,509.293 514.244,509.179 514.504,461.733 459.173,460.669 459.367,509.293" fill="none" stroke="green" stroke-width="3" />
<text x="459.366730" y="509.293365" fill="green" font-size="12">48614</text>
<polyline points="345.979,609.103 405.024,605.901 403.759,558.341 344.48,560.164 345.979,609.103" fill="none" stroke="green" stroke-width="3" />
<text x="345.979401" y="609.102905" fill="green" font-size="12">48617</text>
<polyline points="563.161,597.582 610.9,594.896 611.962,552.58 564.201,553.876 563.161,597.582" fill="none" stroke="green" stroke-width="3" />
<text x="563.161377" y="597.582275" fill="green" font-size="12">48619</text>
<polyline points="189.934,153.998 264.651,164.868 262.333,100.89 186.154,87.7557 189.934,153.998" fill="none" stroke="green" stroke-width="3" />
<text x="189.934280" y="153.998489" fill="green" font-size="12">48600</text>
<polyline points="455.992,194.898 516.006,204.447 517.363,148.153 456.641,137.074 455.992,194.898" fill="none" stroke="green" stroke-width="3" />
<text x="455.991943" y="194.898392" fill="green" font-size="12">48602</text>
<polyline points="397.465,297.088 397.123,241.078 331.988,232.474 333.097,290.031 397.465,297.088" fill="none" stroke="green" stroke-width="3" />
<text x="397.465179" y="297.087921" fill="green" font-size="12">48605</text>
<polyline points="567.306,315.168 617.386,319.512 620.054,271.186 568.263,263.97 567.306,315.168" fill="none" stroke="green" stroke-width="3" />
<text x="567.305542" y="315.167755" fill="green" font-size="12">48607</text>
<polyline points="202.025,393.381 272.37,397.377 269.13,341.367 198.806,335.072 202.025,393.381" fill="none" stroke="green" stroke-width="3" />
<text x="202.024750" y="393.381042" fill="green" font-size="12">48608</text>
<polyline points="457.867,407.818 514.041,410.63 514.124,360.507 457.134,355.766 457.867,407.818" fill="none" stroke="green" stroke-width="3" />
<text x="457.866730" y="407.818268" fill="green" font-size="12">48610</text>
<polyline points="402.016,506.21 401.382,455.519 338.221,453.206 339.82,505.708 402.016,506.21" fill="none" stroke="green" stroke-width="3" />
<text x="402.015625" y="506.210236" fill="green" font-size="12">48613</text>
<polyline points="563.043,506.113 612.937,506.487 613.699,460.625 563.893,459.445 563.043,506.113" fill="none" stroke="green" stroke-width="3" />
<text x="563.043274" y="506.112549" fill="green" font-size="12">48615</text>
<polyline points="215.949,610.146 282.119,607.427 278.762,556.716 212.549,558.182 215.949,610.146" fill="none" stroke="green" stroke-width="3" />
<text x="215.949295" y="610.146484" fill="green" font-size="12">48616</text>
<polyline points="458.576,599.804 511.78,597.28 512.143,551.942 458.492,553.418 458.576,599.804" fill="none" stroke="green" stroke-width="3" />
<text x="458.575623" y="599.804138" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.30152949436
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-10.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="222.523,260.372 216.912,217.635 174.018,221.707 181.275,263.783 222.523,260.372" fill="none" stroke="green" stroke-width="3" />
<text x="222.522720" y="260.372314" fill="green" font-size="12">48601</text>
<polyline points="197.28,89.311 187.799,43.7878 145.962,47.1627 153.748,92.1406 197.28,89.311" fill="none" stroke="green" stroke-width="3" />
<text x="197.280319" y="89.311028" fill="green" font-size="12">48603</text>
<polyline points="317.014,337.112 311.372,295.127 269.805,298.668 276.05,340.646 317.014,337.112" fill="none" stroke="green" stroke-width="3" />
<text x="317.013885" y="337.112396" fill="green" font-size="12">48604</text>
<polyline points="295.508,169.239 289.733,124.955 245.201,128.285 251.416,172.433 295.508,169.239" fill="none" stroke="green" stroke-width="3" />
<text x="295.507935" y="169.239349" fill="green" font-size="12">48606</text>
<polyline points="389.96,246.367 384.329,203.367 341.378,206.95 347.696,249.611 389.96,246.367" fill="none" stroke="green" stroke-width="3" />
<text x="389.959595" y="246.366608" fill="green" font-size="12">48609</text>
<polyline points="366.48,74.5726 360.948,32.7228 317.286,34.8362 324.416,77.9818 366.48,74.5726" fill="none" stroke="green" stroke-width="3" />
<text x="366.480438" y="74.572601" fill="green" font-size="12">48611</text>
<polyline points="484.815,323.148 479.275,281.422 436.59,284.787 443.134,326.351 484.815,323.148" fill="none" stroke="green" stroke-width="3" />
<text x="484.815125" y="323.147705" fill="green" font-size="12">48612</text>
<polyline points="463.89,155.441 457.598,110.989 414.331,114.292 420.063,158.543 463.89,155.441" fill="none" stroke="green" stroke-width="3" />
<text x="463.889557" y="155.440750" fill="green" font-size="12">48614</text>
<polyline points="557.536,233.393 551.556,189.926 509.016,193.278 514.665,236.345 557.536,233.393" fill="none" stroke="green" stroke-width="3" />
<text x="557.535583" y="233.393188" fill="green" font-size="12">48617</text>
<polyline points="535.22,60.7091 529.013,17.2774 487.738,20.1942 492.589,64.0113 535.22,60.7091" fill="none" stroke="green" stroke-width="3" />
<text x="535.220459" y="60.709080" fill="green" font-size="12">48619</text>
<polyline points="209.138,172.819 202.463,127.248 158.11,131.195 165.383,176.04 209.138,172.819" fill="none" stroke="green" stroke-width="3" />
<text x="209.137878" y="172.819244" fill="green" font-size="12">48602</text>
<polyline points="261.948,254.224 304.561,250.986 299.075,207.864 256.2,211.195 261.948,254.224" fill="none" stroke="green" stroke-width="3" />
<text x="261.948456" y="254.223755" fill="green" font-size="12">48605</text>
<polyline points="280.276,78.5277 273.482,34.8403 230.918,37.4325 237.351,81.8099 280.276,78.5277" fill="none" stroke="green" stroke-width="3" />
<text x="280.276367" y="78.527657" fill="green" font-size="12">48607</text>
<polyline points="398.571,327.622 393.539,285.167 350.829,288.531 356.646,330.593 398.571,327.622" fill="none" stroke="green" stroke-width="3" />
<text x="398.570862" y="327.621948" fill="green" font-size="12">48608</text>
<polyline points="378.839,160.236 372.627,115.519 328.745,119.236 334.531,162.976 378.839,160.236" fill="none" stroke="green" stroke-width="3" />
<text x="378.838562" y="160.236038" fill="green" font-size="12">48610</text>
<polyline points="429.17,240.374 472.259,237.323 467.007,194.252 423.7,197.54 429.17,240.374" fill="none" stroke="green" stroke-width="3" />
<text x="429.169769" y="240.373611" fill="green" font-size="12">48613</text>
<polyline points="449.749,65.4532 443.392,21.9607 402.644,25.9096 406.869,68.6769 449.749,65.4532" fill="none" stroke="green" stroke-width="3" />
<text x="449.748932" y="65.453217" fill="green" font-size="12">48615</text>
<polyline points="565.843,314.411 560.579,272.552 518.264,275.53 524.113,317.545 565.843,314.411" fill="none" stroke="green" stroke-width="3" />
<text x="565.842590" y="314.410583" fill="green" font-size="12">48616</text>
<polyline points="545.751,146.685 538.839,101.83 496.324,105.396 501.664,149.68 545.751,146.685" fill="none" stroke="green" stroke-width="3" />
<text x="545.750671" y="146.685135" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.70201751052
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-11.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="109.224,440.647 102.671,390.23 35.9776,389.302 40.6165,440.269 109.224,440.647" fill="none" stroke="green" stroke-width="3" />
<text x="109.223740" y="440.646667" fill="green" font-size="12">48601</text>
<polyline points="89.1455,245.274 86.6879,196.433 16.7397,188.122 21.451,238.642 89.1455,245.274" fill="none" stroke="green" stroke-width="3" />
<text x="89.145515" y="245.273972" fill="green" font-size="12">48603</text>
<polyline points="237.444,532.384 232.67,485.309 172.758,486.599 177.778,534.575 237.444,532.384" fill="none" stroke="green" stroke-width="3" />
<text x="237.443558" y="532.384338" fill="green" font-size="12">48604</text>
<polyline points="216.631,347.064 212.562,302.017 154.301,297.594 158.851,344.357 216.631,347.064" fill="none" stroke="green" stroke-width="3" />
<text x="216.630951" y="347.064301" fill="green" font-size="12">48606</text>
<polyline points="337.795,439.96 330.585,395.771 277.674,394.691 282.245,439.68 337.795,439.96" fill="none" stroke="green" stroke-width="3" />
<text x="337.794800" y="439.960144" fill="green" font-size="12">48609</text>
<polyline points="315.488,266.903 311.849,224.639 259.014,217.852 263.363,262.02 315.488,266.903" fill="none" stroke="green" stroke-width="3" />
<text x="315.487518" y="266.903290" fill="green" font-size="12">48611</text>
<polyline points="444.487,522.683 439.544,480.798 390.689,481.531 395.723,524.38 444.487,522.683" fill="none" stroke="green" stroke-width="3" />
<text x="444.486633" y="522.683228" fill="green" font-size="12">48612</text>
<polyline points="424.254,357.528 418.145,316.254 370.656,312.942 375.639,354.946 424.254,357.528" fill="none" stroke="green" stroke-width="3" />
<text x="424.254028" y="357.527649" fill="green" font-size="12">48614</text>
<polyline points="524.131,440.143 518.483,400.44 474.786,399.468 479.742,439.829 524.131,440.143" fill="none" stroke="green" stroke-width="3" />
<text x="524.130798" y="440.142609" fill="green" font-size="12">48617</text>
<polyline points="503.282,284.007 498.349,245.13 454.578,240.281 459.621,279.853 503.282,284.007" fill="none" stroke="green" stroke-width="3" />
<text x="503.282379" y="284.006531" fill="green" font-size="12">48619</text>
<polyline points="113.413,536.891 108.2,486.684 41.2089,487.801 46.0645,539.5 113.413,536.891" fill="none" stroke="green" stroke-width="3" />
<text x="113.413376" y="536.890869" fill="green" font-size="12">48600</text>
<polyline points="161.438,390.917 165.37,439.293 226.656,439.598 220.325,392.921 161.438,390.917" fill="none" stroke="green" stroke-width="3" />
<text x="161.437576" y="390.916840" fill="green" font-size="12">48605</text>
<polyline points="207.906,256.612 204.111,210.875 143.436,203.321 148.534,250.846 207.906,256.612" fill="none" stroke="green" stroke-width="3" />
<text x="207.905884" y="256.611755" fill="green" font-size="12">48607</text>
<polyline points="344.03,528.151 338.21,483.178 283.31,483.638 288.533,530.062 344.03,528.151" fill="none" stroke="green" stroke-width="3" />
<text x="344.029724" y="528.150574" fill="green" font-size="12">48608</text>
<polyline points="325.236,353.673 320.333,310.113 267.727,306.292 271.578,350.06 325.236,353.673" fill="none" stroke="green" stroke-width="3" />
<text x="325.236298" y="353.672607" fill="green" font-size="12">48610</text>
<polyline points="379.694,397.919 383.775,440.47 433.692,441.264 428.466,399.601 379.694,397.919" fill="none" stroke="green" stroke-width="3" />
<text x="379.693573" y="397.918732" fill="green" font-size="12">48613</text>
<polyline points="414.263,276.515 410.385,236.083 362.791,231.432 366.332,272.093 414.263,276.515" fill="none" stroke="green" stroke-width="3" />
<text x="414.263428" y="276.515167" fill="green" font-size="12">48615</text>
<polyline points="532.209,521.014 527.509,481.012 482.64,481.267 487.556,522.566 532.209,521.014" fill="none" stroke="green" stroke-width="3" />
<text x="532.209351" y="521.014099" fill="green" font-size="12">48616</text>
<polyline points="513.143,363.443 506.917,323.424 463.47,320.164 468.795,360.542 513.143,363.443" fill="none" stroke="green" stroke-width="3" />
<text x="513.142700" y="363.443085" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.83027038725
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-12.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="449.389,528.154 414.49,532.364 415.015,578.261 449.636,574.586 449.389,528.154" fill="none" stroke="green" stroke-width="3" />
<text x="449.389191" y="528.153564" fill="green" font-size="12">48601</text>
<polyline points="318.298,545.141 285.711,548.773 287.065,591.858 318.288,588.834 318.298,545.141" fill="none" stroke="green" stroke-width="3" />
<text x="318.298492" y="545.140564" fill="green" font-size="12">48603</text>
<polyline points="519.482,422.83 481.858,429.777 483.058,476.621 519.695,471.04 519.482,422.83" fill="none" stroke="green" stroke-width="3" />
<text x="519.482239" y="422.830261" fill="green" font-size="12">48604</text>
<polyline points="381.949,447.838 349.403,453.597 349.204,497.17 381.573,492.473 381.949,447.838" fill="none" stroke="green" stroke-width="3" />
<text x="381.949127" y="447.837952" fill="green" font-size="12">48606</text>
<polyline points="445.61,345.667 411.475,352.892 412.795,397.474 446.471,390.547 445.61,345.667" fill="none" stroke="green" stroke-width="3" />
<text x="445.609863" y="345.667053" fill="green" font-size="12">48609</text>
<polyline points="316.837,373.322 289.007,380.853 288.867,422.391 316.957,416.265 316.837,373.322" fill="none" stroke="green" stroke-width="3" />
<text x="316.837280" y="373.322449" fill="green" font-size="12">48611</text>
<polyline points="513.637,237.215 477.862,246.604 479.161,291.914 514.729,282.953 513.637,237.215" fill="none" stroke="green" stroke-width="3" />
<text x="513.637085" y="237.214569" fill="green" font-size="12">48612</text>
<polyline points="379.272,273.819 347.61,282.036 347.336,323.899 379.685,316.917 379.272,273.819" fill="none" stroke="green" stroke-width="3" />
<text x="379.272125" y="273.819183" fill="green" font-size="12">48614</text>
<polyline points="445.219,168.574 411.057,178.722 411.071,222.259 444.655,212.678 445.219,168.574" fill="none" stroke="green" stroke-width="3" />
<text x="445.219391" y="168.574158" fill="green" font-size="12">48617</text>
<polyline points="319.947,208.123 291.098,217.633 290.435,258.082 318.112,249.028 319.947,208.123" fill="none" stroke="green" stroke-width="3" />
<text x="319.946808" y="208.123108" fill="green" font-size="12">48619</text>
<polyline points="520.16,516.529 482.062,521.703 482.69,569.466 521.101,565.677 520.16,516.529" fill="none" stroke="green" stroke-width="3" />
<text x="520.159790" y="516.529175" fill="green" font-size="12">48600</text>
<polyline points="378.363,535.925 345.495,539.721 345.66,584.986 378.31,580.68 378.363,535.925" fill="none" stroke="green" stroke-width="3" />
<text x="378.363037" y="535.925354" fill="green" font-size="12">48602</text>
<polyline points="411.418,485.898 447.39,480.926 447.015,433.877 411.215,440.614 411.418,485.898" fill="none" stroke="green" stroke-width="3" />
<text x="411.418060" y="485.897827" fill="green" font-size="12">48605</text>
<polyline points="315.152,456.268 284.45,461.874 283.119,504.58 315.379,500.74 315.152,456.268" fill="none" stroke="green" stroke-width="3" />
<text x="315.152313" y="456.267578" fill="green" font-size="12">48607</text>
<polyline points="515.25,326.969 479.144,336.377 479.984,382.217 516.885,374.439 515.25,326.969" fill="none" stroke="green" stroke-width="3" />
<text x="515.249817" y="326.969238" fill="green" font-size="12">48608</text>
<polyline points="378.053,358.908 345.932,365.576 346.316,409.457 378.004,402.934 378.053,358.908" fill="none" stroke="green" stroke-width="3" />
<text x="378.052521" y="358.907959" fill="green" font-size="12">48610</text>
<polyline points="409.84,307.328 444.107,299.49 443.746,254.414 409.587,263.626 409.84,307.328" fill="none" stroke="green" stroke-width="3" />
<text x="409.839600" y="307.328125" fill="green" font-size="12">48613</text>
<polyline points="513.789,145.979 477.289,157.132 477.219,201.516 513.863,191.889 513.789,145.979" fill="none" stroke="green" stroke-width="3" />
<text x="513.788574" y="145.978683" fill="green" font-size="12">48616</text>
<polyline points="379.252,187.789 346.92,197.151 346.528,238.513 378.183,230.733 379.252,187.789" fill="none" stroke="green" stroke-width="3" />
<text x="379.252136" y="187.789291" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.34260804628
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-13.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1052.53,157.188 1052.23,193.389 1095.32,193.191 1094.95,156.971 1052.53,157.188" fill="none" stroke="green" stroke-width="3" />
<text x="1052.528687" y="157.187790" fill="green" font-size="12">48601</text>
<polyline points="1052.21,305.428 1052.46,343.464 1096.25,343.87 1096.29,305.013 1052.21,305.428" fill="none" stroke="green" stroke-width="3" />
<text x="1052.206787" y="305.428101" fill="green" font-size="12">48603</text>
<polyline points="971.912,90.9223 970.733,125.06 1012.17,125.208 1012.15,89.8128 971.912,90.9223" fill="none" stroke="green" stroke-width="3" />
<text x="971.912415" y="90.922264" fill="green" font-size="12">48604</text>
<polyline points="967.488,230.942 966.609,267.274 1009.64,268.242 1010.37,231.057 967.488,230.942" fill="none" stroke="green" stroke-width="3" />
<text x="967.488159" y="230.941681" fill="green" font-size="12">48606</text>
<polyline points="887.061,157.464 885.002,193.691 927.278,194.286 928.883,157.873 887.061,157.464" fill="none" stroke="green" stroke-width="3" />
<text x="887.060913" y="157.463745" fill="green" font-size="12">48609</text>
<polyline points="878.816,303.766 877.17,343.88 920.487,344.197 922.152,303.888 878.816,303.766" fill="none" stroke="green" stroke-width="3" />
<text x="878.815857" y="303.766144" fill="green" font-size="12">48611</text>
<polyline points="810.125,86.6928 807.38,121.667 848.813,123.066 850.246,87.9601 810.125,86.6928" fill="none" stroke="green" stroke-width="3" />
<text x="810.125427" y="86.692841" fill="green" font-size="12">48612</text>
<polyline points="798.754,228.354 796.159,265.858 838.738,266.165 841.599,229.331 798.754,228.354" fill="none" stroke="green" stroke-width="3" />
<text x="798.753723" y="228.354401" fill="green" font-size="12">48614</text>
<polyline points="721.826,153.315 717.892,189.538 760.465,191.226 763.653,155.107 721.826,153.315" fill="none" stroke="green" stroke-width="3" />
<text x="721.825806" y="153.315475" fill="green" font-size="12">48617</text>
<polyline points="706.293,301.517 702.404,340.029 745.532,341.485 749.751,302.559 706.293,301.517" fill="none" stroke="green" stroke-width="3" />
<text x="706.293152" y="301.516876" fill="green" font-size="12">48619</text>
<polyline points="1053.5,88.3083 1053.45,123.143 1095.53,123.321 1094.5,87.8459 1053.5,88.3083" fill="none" stroke="green" stroke-width="3" />
<text x="1053.495850" y="88.308304" fill="green" font-size="12">48600</text>
<polyline points="1052.95,228.853 1053.2,266.806 1097.09,266.56 1096.56,228.912 1052.95,228.853" fill="none" stroke="green" stroke-width="3" />
<text x="1052.954712" y="228.852646" fill="green" font-size="12">48602</text>
<polyline points="970.637,157.803 969.213,195.071 1012.38,194.867 1013.17,157.97 970.637,157.803" fill="none" stroke="green" stroke-width="3" />
<text x="970.636841" y="157.802673" fill="green" font-size="12">48605</text>
<polyline points="966.161,303.23 965.944,343.331 1010.09,343.322 1010.21,303.838 966.161,303.23" fill="none" stroke="green" stroke-width="3" />
<text x="966.160828" y="303.230164" fill="green" font-size="12">48607</text>
<polyline points="891.915,88.7228 890.529,123.506 931.589,123.981 933.158,89.8362 891.915,88.7228" fill="none" stroke="green" stroke-width="3" />
<text x="891.915039" y="88.722786" fill="green" font-size="12">48608</text>
<polyline points="884.257,228.931 882.192,266.481 925.678,266.907 927.533,229.211 884.257,228.931" fill="none" stroke="green" stroke-width="3" />
<text x="884.256775" y="228.930695" fill="green" font-size="12">48610</text>
<polyline points="805.874,155.011 802.851,191.792 845.85,193.099 848.044,155.621 805.874,155.011" fill="none" stroke="green" stroke-width="3" />
<text x="805.874146" y="155.010681" fill="green" font-size="12">48613</text>
<polyline points="793.88,301.763 790.62,341.099 835.07,342.259 837.309,302.492 793.88,301.763" fill="none" stroke="green" stroke-width="3" />
<text x="793.880493" y="301.762512" fill="green" font-size="12">48615</text>
<polyline points="730.911,84.6644 727.124,119.45 768.819,120.577 771.829,85.5472 730.911,84.6644" fill="none" stroke="green" stroke-width="3" />
<text x="730.910706" y="84.664383" fill="green" font-size="12">48616</text>
<polyline points="715.602,225.177 711.426,262.848 755.006,263.613 758.854,226.392 715.602,225.177" fill="none" stroke="green" stroke-width="3" />
<text x="715.602051" y="225.177017" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 0.738898030151
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-14.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1553.72,133.092 1563.61,174.092 1613.6,157.766 1603.34,115.987 1553.72,133.092" fill="none" stroke="green" stroke-width="3" />
<text x="1553.724854" y="133.092209" fill="green" font-size="12">48601</text>
<polyline points="1593.31,295.632 1603.91,336.236 1654.12,323.394 1643.9,281.475 1593.31,295.632" fill="none" stroke="green" stroke-width="3" />
<text x="1593.311890" y="295.631622" fill="green" font-size="12">48603</text>
<polyline points="1445.19,90.0333 1453.12,128.696 1499.08,111.816 1489.56,72.2503 1445.19,90.0333" fill="none" stroke="green" stroke-width="3" />
<text x="1445.189575" y="90.033272" fill="green" font-size="12">48604</text>
<polyline points="1479.96,243.633 1489.17,282.961 1535.71,269.141 1526.81,228.814 1479.96,243.633" fill="none" stroke="green" stroke-width="3" />
<text x="1479.963989" y="243.632904" fill="green" font-size="12">48606</text>
<polyline points="1376.45,196.288 1384.53,234.247 1427.94,220.01 1419.45,181.131 1376.45,196.288" fill="none" stroke="green" stroke-width="3" />
<text x="1376.445190" y="196.288300" fill="green" font-size="12">48609</text>
<polyline points="1409.14,346.993 1417.65,385.809 1461.91,374.345 1452.72,334.926 1409.14,346.993" fill="none" stroke="green" stroke-width="3" />
<text x="1409.137939" y="346.993469" fill="green" font-size="12">48611</text>
<polyline points="1281.34,152.544 1288.94,189.175 1328.66,174.741 1320.71,137.811 1281.34,152.544" fill="none" stroke="green" stroke-width="3" />
<text x="1281.339722" y="152.543762" fill="green" font-size="12">48612</text>
<polyline points="1311.62,297.277 1319.5,333.456 1359.37,321.428 1351.73,284.654 1311.62,297.277" fill="none" stroke="green" stroke-width="3" />
<text x="1311.624146" y="297.276917" fill="green" font-size="12">48614</text>
<polyline points="1221.93,250.747 1228.88,285.993 1265.77,273.631 1258.83,237.938 1221.93,250.747" fill="none" stroke="green" stroke-width="3" />
<text x="1221.931274" y="250.747498" fill="green" font-size="12">48617</text>
<polyline points="1250.69,392.101 1257.74,428.166 1295.69,418.072 1288.29,381.367 1250.69,392.101" fill="none" stroke="green" stroke-width="3" />
<text x="1250.692993" y="392.101196" fill="green" font-size="12">48619</text>
<polyline points="1535.4,54.9133 1544.86,94.5622 1593.63,76.5964 1583.18,36.7477 1535.4,54.9133" fill="none" stroke="green" stroke-width="3" />
<text x="1535.401978" y="54.913307" fill="green" font-size="12">48600</text>
<polyline points="1572.68,213.413 1582.85,254.925 1633.83,239.938 1623.56,197.78 1572.68,213.413" fill="none" stroke="green" stroke-width="3" />
<text x="1572.679565" y="213.412918" fill="green" font-size="12">48602</text>
<polyline points="1469.94,206.516 1516.98,191.118 1507.94,150.146 1460.89,166.988 1469.94,206.516" fill="none" stroke="green" stroke-width="3" />
<text x="1469.938721" y="206.515533" fill="green" font-size="12">48605</text>
<polyline points="1498.98,321.366 1506.4,362.501 1555.1,348.82 1545.04,308.361 1498.98,321.366" fill="none" stroke="green" stroke-width="3" />
<text x="1498.980103" y="321.365814" fill="green" font-size="12">48607</text>
<polyline points="1359.45,122.671 1367.42,161.219 1410.52,145.492 1401.59,106.996 1359.45,122.671" fill="none" stroke="green" stroke-width="3" />
<text x="1359.451660" y="122.670517" fill="green" font-size="12">48608</text>
<polyline points="1391.82,272.122 1400.07,310.095 1443.51,297.098 1435.31,258.224 1391.82,272.122" fill="none" stroke="green" stroke-width="3" />
<text x="1391.823120" y="272.121887" fill="green" font-size="12">48610</text>
<polyline points="1303.32,261.778 1343.9,248.56 1336.25,210.368 1295.94,224.415 1303.32,261.778" fill="none" stroke="green" stroke-width="3" />
<text x="1303.319336" y="261.778351" fill="green" font-size="12">48613</text>
<polyline points="1326.47,370.716 1334.26,408.357 1375.25,397.868 1367.29,359.333 1326.47,370.716" fill="none" stroke="green" stroke-width="3" />
<text x="1326.474976" y="370.715607" fill="green" font-size="12">48615</text>
<polyline points="1207.62,180.704 1214.55,216.824 1252.01,203.147 1244.75,166.555 1207.62,180.704" fill="none" stroke="green" stroke-width="3" />
<text x="1207.622070" y="180.703964" fill="green" font-size="12">48616</text>
<polyline points="1236.03,321.214 1243.16,356.981 1280.84,346.027 1273.31,309.48 1236.03,321.214" fill="none" stroke="green" stroke-width="3" />
<text x="1236.033203" y="321.214142" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.62738649114
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-15.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1255.7,388.137 1251.02,445.53 1307.39,443.853 1312.76,386.928 1255.7,388.137" fill="none" stroke="green" stroke-width="3" />
<text x="1255.699829" y="388.136688" fill="green" font-size="12">48601</text>
<polyline points="1239.73,601.371 1236.68,651.07 1287.76,649.577 1292.41,600.228 1239.73,601.371" fill="none" stroke="green" stroke-width="3" />
<text x="1239.727051" y="601.371399" fill="green" font-size="12">48603</text>
<polyline points="1147.26,271.473 1145.18,332.074 1202.91,330.966 1206.82,270.446 1147.26,271.473" fill="none" stroke="green" stroke-width="3" />
<text x="1147.258789" y="271.473053" fill="green" font-size="12">48604</text>
<polyline points="1137.67,501.255 1135.62,553.909 1189.95,552.754 1193.53,499.673 1137.67,501.255" fill="none" stroke="green" stroke-width="3" />
<text x="1137.674683" y="501.254913" fill="green" font-size="12">48606</text>
<polyline points="1029.64,393.476 1029.01,450.736 1085.34,449.411 1086.36,392.575 1029.64,393.476" fill="none" stroke="green" stroke-width="3" />
<text x="1029.636353" y="393.476013" fill="green" font-size="12">48609</text>
<polyline points="1029.09,606.413 1028.92,654.209 1080.77,652.989 1082.07,605.387 1029.09,606.413" fill="none" stroke="green" stroke-width="3" />
<text x="1029.088501" y="606.413452" fill="green" font-size="12">48611</text>
<polyline points="911.075,276.23 913.477,337.422 971.42,335.891 970.828,275.242 911.075,276.23" fill="none" stroke="green" stroke-width="3" />
<text x="911.075012" y="276.230469" fill="green" font-size="12">48612</text>
<polyline points="919.15,506 921.341,559.042 976.094,557.775 975.237,504.786 919.15,506" fill="none" stroke="green" stroke-width="3" />
<text x="919.149841" y="505.999939" fill="green" font-size="12">48614</text>
<polyline points="800.865,398.154 804.965,455.395 862.443,455.207 858.716,397.235 800.865,398.154" fill="none" stroke="green" stroke-width="3" />
<text x="800.865417" y="398.153564" fill="green" font-size="12">48617</text>
<polyline points="817.13,611.343 820.856,659.969 873.256,658.937 870.209,610.112 817.13,611.343" fill="none" stroke="green" stroke-width="3" />
<text x="817.130249" y="611.342651" fill="green" font-size="12">48619</text>
<polyline points="1262.01,271.153 1257.41,331.515 1315.75,330.243 1321.73,269.976 1262.01,271.153" fill="none" stroke="green" stroke-width="3" />
<text x="1262.005249" y="271.153259" fill="green" font-size="12">48600</text>
<polyline points="1243.67,499.388 1239.41,552.76 1294.4,552.084 1299.76,498.953 1243.67,499.388" fill="none" stroke="green" stroke-width="3" />
<text x="1243.669922" y="499.388092" fill="green" font-size="12">48602</text>
<polyline points="1135.97,449.677 1193.04,449.324 1196.57,391.738 1139,392.404 1135.97,449.677" fill="none" stroke="green" stroke-width="3" />
<text x="1135.966187" y="449.677094" fill="green" font-size="12">48605</text>
<polyline points="1131.02,604.597 1127.74,654.367 1180.69,652.846 1184.05,603.718 1131.02,604.597" fill="none" stroke="green" stroke-width="3" />
<text x="1131.020508" y="604.596680" fill="green" font-size="12">48607</text>
<polyline points="1026.43,275.977 1026.09,337.427 1084.48,335.21 1086.13,275.842 1026.43,275.977" fill="none" stroke="green" stroke-width="3" />
<text x="1026.432983" y="275.976837" fill="green" font-size="12">48608</text>
<polyline points="1024.88,504.724 1024.79,557.832 1079.8,557.027 1081.06,503.469 1024.88,504.724" fill="none" stroke="green" stroke-width="3" />
<text x="1024.884399" y="504.723969" fill="green" font-size="12">48610</text>
<polyline points="913.945,453.659 971.481,453.367 970.403,394.959 912.237,395.764 913.945,453.659" fill="none" stroke="green" stroke-width="3" />
<text x="913.944580" y="453.659027" fill="green" font-size="12">48613</text>
<polyline points="919.647,609.295 920.405,659.233 972.941,657.444 972.74,608.38 919.647,609.295" fill="none" stroke="green" stroke-width="3" />
<text x="919.646973" y="609.295410" fill="green" font-size="12">48615</text>
<polyline points="789.46,276.95 793.62,339.281 853.132,339.043 849.148,276.958 789.46,276.95" fill="none" stroke="green" stroke-width="3" />
<text x="789.459595" y="276.949677" fill="green" font-size="12">48616</text>
<polyline points="806.015,508.322 809.568,561.605 864.443,561.062 862.566,507.445 806.015,508.322" fill="none" stroke="green" stroke-width="3" />
<text x="806.015076" y="508.322021" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
</ol>
} pose {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg} height 1080 coords {806.015,508.322 809.568,561.605 864.443,561.062 862.566,507.445 806.015,508.322}}}
when /somebody/ claims the default program geometry is /geom/ {
$collectLib ScheduleRecollect (
[ m674:0 () ]
[ m678:0 () ]
[ m927:0 () ]
)when /somebody/ claims the default program geometry is /geom/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {/somebody/ claims the default program geometry is /geom/} settle 0ms} {settleMs 0 settleNs 0}}
when program /program/ is scaled by x /xScale/ y /yScale/ {
proc extractMm {mm} {
regexp ()when program /program/ is scaled by x /xScale/ y /yScale/ {
proc extractMm {mm} {
regexp {([0-9.]+)mm} $mm -> extracted
return $extracted
}
set tagSize [extractMm [dict get $defaultGeom tagSize]]
set left [extractMm [dict get $defaultGeom left]]
set right [extractMm [dict get $defaultGeom right]]
set top [extractMm [dict get $defaultGeom top]]
set bottom [extractMm [dict get $defaultGeom bottom]]
set width [expr {$left + $tagSize + $right}]
set height [expr {$top + $tagSize + $bottom}]
set right $($right + ($width * $xScale - $width))mm
set bottom $($bottom + ($height * $yScale - $height))mm
set newGeom [list tagSize ${tagSize}mm left ${left}mm right ${right}mm top ${top}mm bottom ${bottom}mm]
Claim tag $program has geometry $newGeom
} with environment {{this builtin-programs/tags-geometry.folk} {} {} {defaultGeom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}} {}}
when camera /camera/ has width /cameraWidth/ height /cameraHeight/ {When display /display/ has width (
[ m1675:0 (s2610:0) ]
)when camera /camera/ has width /cameraWidth/ height /cameraHeight/ {When display /display/ has width /displayWidth/ height /displayHeight/ & the AprilTag detector maker is /makeAprilTagDetector/ & the jpeg library is /jpegLib/ & the calibration model library is /modelLib/ & the calibration matrix library is /matLib/ & /someone/ wishes to calibrate camera {$camera} to display /display/ using measurements /measurements/ \n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/calibrate/calibrate.folk} {} {p det}}
when camera /camera/ has width /cameraWidth/ height /cameraHeight/ {When camera {$camera} has intrins (
[ m1676:0 (s2608:0) ]
)when camera /camera/ has width /cameraWidth/ height /cameraHeight/ {When camera {$camera} has intrinsics /cameraIntrinsics/ \n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[ (
[ m28247:1058 () ]
[ m28417:1058 () ]
[ m28536:1067 () ]
[ m28709:1065 () ]
[ m28875:1067 () ]
[ m29100:1067 () ]
)when camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[__whenOfCurrentMatchIncompleteChildMatchesCount\]\ >\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13} {__results {}} {} {imageLib <C:cfileV8MUaU>} {}}
when camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[ (
[ m28375:1067 () ]
[ m28535:1067 () ]
[ m28634:1067 () ]
[ m28864:1067 () ]
[ m28874:1066 () ]
[ m29027:1066 () ]
)when camera /camera/ has gray frame /frame/ at timestamp /frameTs/ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[__whenOfCurrentMatchIncompleteChildMatchesCount\]\ >\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n with environment {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} entireFrameDetector <C:cfilemMw4ED> ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} incrementalDetector <C:cfile7Br5fn> tagFamily tagStandard52h13} {__results {}} {}}
when camera /camera/ to display /display/ has extrinsics /extrinsics/ \n\ \ \ \ package\ require\ lin (
[ m1385:0 (s2241:0 s2242:0) ]
)when camera /camera/ to display /display/ has extrinsics /extrinsics/ \n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when camera /cameraPath/ has width /decompWidth/ height /decompHeight/ \n\ \ \ \ When\ camera\ \$came (
[ m1677:0 (s2607:0 s2609:0) ]
)when camera /cameraPath/ has width /decompWidth/ height /decompHeight/ \n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {jpegLib <C:cfileZXB3iE>} {camLib <C:cfilel9mgpH> camc ::<reference.<C______>.00000000000000000002>}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has jpeg frame /jpeg/ at tim (
[ m28331:1067 () ]
[ m28506:1050 () ]
[ m28611:1050 () ]
[ m28837:1065 () ]
[ m28861:1066 () ]
[ m28991:1066 () ]
)when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has jpeg frame /jpeg/ at timestamp /ts/ \n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {jpegLib <C:cfileZXB3iE>} {camLib <C:cfilel9mgpH> camc ::<reference.<C______>.00000000000000000002>} {cameraPath /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 decompWidth 1920 decompHeight 1080} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has jpeg frame /jpeg/ at tim (
[ m29015:1067 () ]
)when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has jpeg frame /jpeg/ at timestamp /ts/ \n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ with environment {{this builtin-programs/camera/usb.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {jpegLib <C:cfileZXB3iE>} {camLib <C:cfilel9mgpH> camc ::<reference.<C______>.00000000000000000002>} {cameraPath /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 decompWidth 1920 decompHeight 1080} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has intrinsics /cameraIntrin (
[ m1678:0 (s2611:0) ]
)when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has intrinsics /cameraIntrinsics/ \n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta (
[ m28733:1067 () ]
[ m28905:1067 () ]
[ m28988:1065 () ]
[ m29076:1067 (s11108:1265) ]
)when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 63} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta (
[ m29073:1065 (s11106:1266) ]
)when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 83} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-6} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-5} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-1} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-4} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-3} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timesta ()when camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has frame /frame/ at timestamp /timestamp/ {When {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-2} {} {cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraIntrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam (
[ m3382:1022 (s32233:1209) ]
)when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 63} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam (
[ m47756:1061 (s64527:1261) ]
)when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 83} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-6} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-5} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-1} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-4} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-3} {}}
when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestam ()when camera /cam/ has intrinsics /cameraIntrinsics/ {When camera {$cam} has frame /frame/ at timestamp /timestamp/ & {$p} has quad /q/ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n} with environment {{this builtin-programs/camera/slice.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {p 54-frame-2} {}}
when When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ we (
[ m687:0 (s1060:0) ]
)when When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n\}\n with environment {{this builtin-programs/calibrate/calibrate-page.folk}}
when #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\ (
[ m693:0 (s1069:0) ]
)when #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\nClaim\ the\ calibration\ model\ library\ is\ \[library\ create\ modelLib\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\n\n\ \ \ \ variable\ ROWS\ 5\n\ \ \ \ variable\ COLS\ 4\n\ \ \ \ proc\ rows\ \{\}\ \{\ variable\ ROWS\;\ return\ \$ROWS\ \}\n\ \ \ \ proc\ cols\ \{\}\ \{\ variable\ COLS\;\ return\ \$COLS\ \}\n\ \ \ \ #\ A\ model\ is\ a\ dictionary\ whose\ keys\ are\ tag\ IDs\ and\ where\ each\n\ \ \ \ #\ value\ is\ a\ dictionary\ with\ keys\ `c`\ and\ `p`\ which\ are\ model\n\ \ \ \ #\ points\ (x,\ y).\n\ \ \ \ proc\ unitModel\ \{\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ set\ UNIT_MODEL\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ \ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ \ \ \ \ set\ pad\ \[expr\ \{\$tagSideLength\ /\ 3\}\]\n\ \ \ \ \ \ \ \ for\ \{set\ row\ 0\}\ \{\$row\ <\ \$ROWS\}\ \{incr\ row\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ col\ 0\}\ \{\$col\ <\ \$COLS\}\ \{incr\ col\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[expr\ \{48600\ +\ \$row*\$COLS\ +\ \$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$row\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ outer\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{\$modelX\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{\$modelY\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ inner\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopLeft\ \[list\ \$modelX\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[list\ \$modelX\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c\ \[scale\ 0.5\ \[add\ \$modelTopLeft\ \$modelBottomRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p\ \[list\ \$modelBottomLeft\ \$modelBottomRight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelTopRight\ \$modelTopLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ UNIT_MODEL\ \$id\ \$modelTag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$UNIT_MODEL\n\ \ \ \ \}\n\ \ \ \ #\ Tags\ with\ isPrintedTag\ will\ get\ projected\ to\ PostScript\ points\n\ \ \ \ #\ and\ printed\;\ tags\ with\ isProjectedTag\ will\ get\ projected\ to\n\ \ \ \ #\ Vulkan\ points\ and\ rendered\ on\ projector.\n\n\ \ \ \ #\ Tag\ operations.\n\ \ \ \ #\ ---------------\n\n\ \ \ \ proc\ isCalibrationTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ return\ \$(\$id\ >=\ 48600\ &&\ \$id\ <\ 48600\ +\ \$ROWS*\$COLS)\n\ \ \ \ \}\n\ \ \ \ proc\ isPrintedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ COLS\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{int(\$idx\ /\ \$COLS)\}\]\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$idx\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$row\ %\ 2\ ==\ 0\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 1)\ :\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 0)\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\ \ \ \ proc\ isProjectedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{!\[isPrintedTag\ \$id\]\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ isVersionTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$idx\ %\ 4\ ==\ 1\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\n\ \ \ \ #\ Model\ operations.\n\ \ \ \ #\ -----------------\n\n\ \ \ \ #\ Takes\ a\ model\ object\ (dictionary\ of\ tag\ ID\ =>\ \{p,\ c\})\ and\n\ \ \ \ #\ rotates\ version\ tags\ according\ to\ version.\n\ \ \ \ proc\ updateModelVersion\ \{model\ version\}\ \{\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ version\ tag.\ Rotate\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$model\ \$id\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rotatedCorners\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 4\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ rotatedCorners\ \[lindex\ \$p\ \[expr\ \{(\$i\ +\ \$version)\ %\ 4\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ model\ \$id\ p\ \$rotatedCorners\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$model\n\ \ \ \ \}\n\ \ \ \ proc\ scaleModel\ \{model\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ c\ \[scale\ \$scale\ \[dict\ get\ \$tag\ c\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ p\ \[scale\ \$scale\ \[dict\ get\ \$tag\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ proc\ countProjectedTags\ \{model\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\}\ \{\ incr\ i\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$i\n\ \ \ \ \}\n\n\ \ \ \ #\ Detected\ tag-list\ operations.\n\ \ \ \ #\ -----------------------------\n\ \ \ \ proc\ filterProjectedTagsInDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ return\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Find\ a\ version\ tag\ that\ the\ camera\ saw\ and\ check\ its\ rotation\ to\n\ \ \ \ #\ figure\ out\ the\ model\ version\ that\ we're\ seeing.\n\ \ \ \ proc\ detectVersionFromDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ local\ proc\ getTagAngle\ \{tag\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{atan2(-1\ *\ (\[lindex\ \$p\ 1\ 1\]\ -\ \[lindex\ \$p\ 0\ 1\]),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$p\ 1\ 0\]\ -\ \[lindex\ \$p\ 0\ 0\])\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Find\ any\ version\ tag.\ If\ none\ were\ detected,\ then\ abort\n\ \ \ \ \ \ \ \ #\ and\ wait\ until\ a\ later\ frame.\n\ \ \ \ \ \ \ \ foreach\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isVersionTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagId\ \$tag(id)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagAngle\ \[getTagAngle\ \$tag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ versionTagId\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ #\ Compare\ angle\ to\ angle\ of\ any\ other\ projected\ tag.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$detectedTags\]\ <\ 2\}\ \{\ return\ \{\}\ \}\n\ \ \ \ \ \ \ \ foreach\ detectedTag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$detectedTag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\ &&\ !\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ otherTagAngle\ \[getTagAngle\ \$detectedTag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ otherTagAngle\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ set\ versionAngle\ \[expr\ \{\$versionTagAngle\ -\ \$otherTagAngle\}\]\n\ \ \ \ \ \ \ \ #\ Rotations\ corresponding\ to\ versions\ 0,\ 1,\ 2,\ 3:\n\ \ \ \ \ \ \ \ set\ possibleVersions\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ 1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ 1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ -1\]\n\ \ \ \ \ \ \ \ #\ Which\ of\ the\ possibleVersions\ is\ versionAngle\ closest\ to?\n\ \ \ \ \ \ \ \ return\ \[lindex\ \[lsort-indices\ \[lmap\ \{x\ y\}\ \$possibleVersions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{sqrt((\$x\ -\ cos(\$versionAngle))**2\ +\ (\$y\ -\ sin(\$versionAngle))**2)\}\n\ \ \ \ \ \ \ \ \}\]\]\ 0\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ meanTagsDifference\ \{tags1\ tags2\}\ \{\n\ \ \ \ \ \ \ \ set\ diffsum\ 0.0\n\ \ \ \ \ \ \ \ set\ ndiffs\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$tags1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ cheat\ and\ only\ count\ printed\ tags\ so\ we\ don't\ have\ to\n\ \ \ \ \ \ \ \ \ \ \ \ #\ deal\ with\ versioning.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$tags2\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x1\ y1\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tags2\ \$id\ c\]\ x2\ y2\n\ \ \ \ \ \ \ \ \ \ \ \ set\ diffsum\ \[expr\ \{\$diffsum\ +\ sqrt((\$x1\ -\ \$x2)*(\$x1\ -\ \$x2)\ +\ (\$y1\ -\ \$y2)*(\$y1\ -\ \$y2))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ ndiffs\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$ndiffs\ ==\ 0\}\ \{\ return\ Inf\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$diffsum\ /\ \$ndiffs\}\]\n\ \ \ \ \}\n\}\]\n with environment {{this builtin-programs/calibrate/model.folk}}
when When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ th (
[ m699:0 (s1078:0) ]
)when When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ calibration\ model\ /model/\ \\\n\ \ \ \ \ \ \ \ using\ model-to-display\ homography\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ with\ message\ /calibrationMessage/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/calibrate/draw-model.folk}}
when #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (o (
[ m705:0 (s1087:0) ]
)when #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (or\n#\ \ \ \ \ projector\ calibration,\ equivalently)\ (see\ Zhengyou\ Zhang)\ using\n#\ \ \ \ \ cmpfit.\n#\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n\}\n with environment {{this builtin-programs/calibrate/refine.folk}}
when {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/ (
[ m711:0 (s1888:0 s1889:0) ]
)when {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
$cc proc enumerateDisplays {} Jim_Obj* {
FOLK_ENSURE(volkInitialize() == VK_SUCCESS);
// Create a minimal Vulkan instance for display enumeration.
VkInstance instance;
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* enabledExtensions[] = {
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#ifdef __APPLE__
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
createInfo.ppEnabledExtensionNames = enabledExtensions;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
if (res == VK_ERROR_EXTENSION_NOT_PRESENT) {
FOLK_ERROR("Unable to enumerate displays (for example, this doesn't work on macOS)");
}
FOLK_ERROR("Failed to create Vulkan instance: %d", res);
}
}
volkLoadInstance(instance);
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
vkDestroyInstance(instance, NULL);
return Jim_NewListObj(interp, NULL, 0);
}
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
Jim_Obj *allDisplaysList = Jim_NewListObj(interp, NULL, 0);
// Enumerate displays for each physical device
for (uint32_t devIdx = 0; devIdx < physicalDeviceCount; devIdx++) {
VkPhysicalDevice physicalDevice = physicalDevices[devIdx];
uint32_t displayCount;
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, NULL);
VkDisplayPropertiesKHR displayProps[displayCount];
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProps);
for (uint32_t i = 0; i < displayCount; i++) {
uint32_t modeCount;
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, NULL);
VkDisplayModePropertiesKHR modeProps[modeCount];
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, modeProps);
Jim_Obj *modesList = Jim_NewListObj(interp, NULL, 0);
for (uint32_t j = 0; j < modeCount; j++) {
Jim_Obj *modeDict = Jim_ObjPrintf("visibleRegion {%u %u} refreshRate %u",
modeProps[j].parameters.visibleRegion.width,
modeProps[j].parameters.visibleRegion.height,
modeProps[j].parameters.refreshRate);
Jim_ListAppendElement(interp, modesList, modeDict);
}
int modesLen;
const char *modesStr = Jim_GetString(modesList, &modesLen);
Jim_Obj *displayDict = Jim_ObjPrintf("name {%s} physicalDimensions {%u %u} "
"physicalResolution {%u %u} modes {%s}",
displayProps[i].displayName ? displayProps[i].displayName : "",
displayProps[i].physicalDimensions.width,
displayProps[i].physicalDimensions.height,
displayProps[i].physicalResolution.width,
displayProps[i].physicalResolution.height,
modesStr);
Jim_ListAppendElement(interp, allDisplaysList, displayDict);
}
}
vkDestroyInstance(instance, NULL);
return allDisplaysList;
}
set displayLib [$cc compile]
if {![catch {exec pkg-config --exists glfw3}]} {
Claim $::thisNode has display glfw with info {name "GLFW (windowed)"}
}
try {
foreach display [$displayLib enumerateDisplays] {
Claim $::thisNode has display $display(name) with info $display
}
} finally {
Claim $::thisNode has had displays enumerated
}
} with environment {{this builtin-programs/gpu/enumerate.folk}}
when When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWi (
[ m717:0 (s1104:0) ]
)when When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n\}\n with environment {{this builtin-programs/calibrate/matlib.folk}}
when #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ ca (
[ m723:0 (s1114:0 s1115:0) ]
)when #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ calibration\n#\ \ \ \ \ pattern\ PDF,\ have\ the\ user\ measure\ its\ real-world\ dimension,\ run\n#\ \ \ \ \ iterative\ projector-camera\ process\ to\ get\ various\ poses\ of\ the\n#\ \ \ \ \ printed\ tags\ alongside\ projected\ tags,\ do\ linear\ fit\ and\ then\n#\ \ \ \ \ nonlinear\ refinement\ to\ find\ intrinsic\ and\ extrinsic\ parameters\n#\ \ \ \ \ for\ the\ camera\ and\ projector.\n#\n#\ \ \ \ \ Closely\ based\ on\ the\ technique\ in\ Audet\ (2009):\n#\ \ \ \ \ http://www.ok.sc.e.titech.ac.jp/res/PCS/publications/procams2009.pdf\n#\n\npackage\ require\ linalg\n\nforeach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\}\ \{\n\ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\}\n\nHold!\ -key\ \{calibration\ poses\ max\}\ \\\n\ \ \ \ Claim\ the\ calibration\ poses\ max\ is\ 10\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ AprilTag\ detector\ maker\ is\ /makeAprilTagDetector/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ calibrate\ camera\ /camera/\ to\ display\ /display/\ \\\n\ \ \ \ \ \ \ \ \ using\ measurements\ /measurements/\ \{\n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nfn\ processHomography\ \{H\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n\}\n\n\n#\ Uses\ Zhang's\ calibration\ technique\n#\ (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf)\n#\ to\ calibrate\ a\ projector\ or\ camera\ given\ a\ known\ 2D\ planar\ pattern\n#\ and\ multiple\ observed\ poses.\n#\n#\ Returns\ intrinsic\ matrix\ for\ the\ camera/projector,\ which\ explains\n#\ how\ 3D\ real-world\ coordinates\ get\ projected\ to\ 2D\ coordinates\ by\n#\ that\ device.\ (The\ intrinsic\ matrix\ can\ be\ used\ with\ an\ AprilTag\n#\ detector\ to\ get\ real-world\ coordinates\ for\ each\ AprilTag.)\n#\n#\ Arguments:\n#\ \ \ \ \ \ \ \ \ width\ \ width\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ height\ height\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ Hs\ \ \ \ \ a\ list\ of\ N\ homographies\ from\ camera/projector\ image\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ plane\ ->\ model\ plane\ (for\ N\ different\ poses).\nfn\ zhangUnrefinedCalibrate\ \{name\ width\ height\ Hs\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n\}\n\nfn\ setCameraToProjectorExtrinsics\ \{modelLib\ calibrationVar\ calibrationPoses\}\ \{\n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n\}\n\n#\ End-to-end\ calibrates\ a\ camera-projector\ pair.\ calibrationPoses\ is\n#\ a\ list\ of\ N\ pose\ dictionaries.\ Each\ pose\ dictionary\ includes\ `tags`\n#\ from\ a\ camera\ detection,\ `model`\ with\ coordinates\ in\ meters,\n#\ `H_modelToDisplay`.\nfn\ unrefinedCalibrateCameraAndProjector\ \{modelLib\ matLib\ calibrationPoses\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n\}\n\nWhen\ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ &\\\n\ \ \ \ \ the\ calibration\ refiner\ is\ /refineCalibration/\ \{\n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n\}\n with environment {{this builtin-programs/calibrate/calibrate.folk}}
when #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ co (
[ m730:0 (s1125:0) ]
)when #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ compilation.\n#\ \ \ \ \ Created\ once\ (not\ per-display).\ Pipelines\ use\ dynamic\ viewport/scissor\n#\ \ \ \ \ so\ they\ work\ across\ displays\ of\ different\ sizes.\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n\}\n with environment {{this builtin-programs/gpu/pipelines.folk}}
when {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq (
[ m736:0 (s1134:0 s1135:0) ]
)when {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq "darwin"} {
# We hard-code gpu.folk into thread 0, so we should abort if not
# running that way.
return
}
fn defineVulkanHandleType {cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
}
Claim the GPU Vulkan handle type definer is [fn defineVulkanHandleType]
fn gpuInit {useGlfw} {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
}
if {$::tcl_platform(os) eq "darwin"} {
gpuInit true
return
}
When $::thisNode has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
}
} with environment {{this builtin-programs/gpu/gpu.folk}}
when folk-sva has had displays enumerated {
# so we know that there isn't an extant Vulkan instan (
[ m1096:0 (s1890:0 s1891:0) ]
)when folk-sva has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
} with environment {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} ^gpuInit {useGlfw {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
} {builtin-programs/gpu/gpu.folk 34}}}}
when folk-sva has display /display/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern (
[ m61851:1043 () ]
)when folk-sva has display /display/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {folk-sva has display /display/ with /...opts/} settle 0ms} {settleMs 0 settleNs 0}}
when folk-sva has camera /camera/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern $s (
[ m61875:969 () ]
[ m61882:1055 () ]
[ m61905:1054 () ]
)when folk-sva has camera /camera/ with /...opts/ {
$collectLib ScheduleRecollect! $pattern $settleNs
On unmatch [list $collectLib ScheduleRecollect! $pattern $settleNs]
} with environment {{this builtin-programs/collect.folk} {} {collectLib <C:cfileQhQ3SS> cc ::<reference.<C______>.00000000000000000002>} {pattern {folk-sva has camera /camera/ with /...opts/} settle 0ms} {settleMs 0 settleNs 0}}
when folk-sva claims printer /name/ is a cups printer with /...options/ {
set command [list /usr/ ()when folk-sva claims printer /name/ is a cups printer with /...options/ {
set command [list /usr/sbin/lpadmin -p $name -E]
if {[dict exists $options url]} {
lappend command -v [dict get $options url]
}
if {[dict exists $options driver]} {
lappend command -m [dict get $options driver]
}
if {[dict exists $options extra-args]} {
lappend command {*}[dict get $options extra-args]
}
exec {*}$command
} with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} ^nextId {{} \n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n {builtin-programs/print/print.folk 188}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}
when When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ (
[ m743:0 (s1145:0) ]
)when When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n\}\n with environment {{this builtin-programs/gpu/textures.folk}}
when #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ an (
[ m750:0 (s1155:0) ]
)when #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ and\n#\ \ \ \ \ numerical\ parameters\ (so\ you\ can\ draw\ images,\ shapes,\ etc.)\n#\ \ \ \ \ Single\ render\ thread\ handles\ all\ displays.\n\nif\ \{\[info\ exists\ this\]\ &&\ \$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ #\ We\ hard-code\ draw.folk\ into\ thread\ 0,\ so\ we\ should\ abort\ if\ not\n\ \ \ \ #\ running\ that\ way.\n\ \ \ \ return\n\}\n\nWhen\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ compiler\ library\ is\ /pipelineCompilerLib/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n\}\n with environment {{this builtin-programs/gpu/draw.folk}}
when #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <stri (
[ m756:0 (s1393:0) ]
)when #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <openssl/sha.h>\n\$cc\ proc\ sha1\ \{char*\ d\}\ Jim_Obj*\ \{\n\ \ \ \ unsigned\ char\ md\[20\]\;\n\ \ \ \ SHA1((unsigned\ char\ *)d,\ strlen(d),\ md)\;\n\ \ \ \ return\ Jim_NewStringObj(interp,\ (char\ *)md,\ 20)\;\n\}\n\$cc\ endcflags\ -lssl\ -lcrypto\nset\ sha1Lib\ \[\$cc\ compile\]\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ \{\n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/gpu/toy-shader.folk}}
when When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n (
[ m764:0 (s1175:0) ]
)when When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/gpu/canvases.folk}}
when When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVul (
[ m770:0 (s1184:0) ]
)when When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n\}\n with environment {{this builtin-programs/gpu/vma.folk}}
when #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif (
[ m777:0 (s1195:0) ]
)when #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ error\ \"Raspberry\ Pi\ camera\ driver\ only\ runs\ on\ Linux.\"\n\}\n\nset\ makeCamera\ \{\n\ \ \ \ set\ cpp\ \[C++\]\n\ \ \ \ \$cpp\ extend\ \$imageLib\n\ \ \ \ \$cpp\ include\ <iostream>\n\ \ \ \ \$cpp\ include\ <iomanip>\n\ \ \ \ \$cpp\ include\ <mutex>\n\ \ \ \ \$cpp\ include\ <condition_variable>\n\ \ \ \ \$cpp\ include\ <queue>\n\ \ \ \ \$cpp\ include\ <sys/mman.h>\n\n\ \ \ \ \$cpp\ include\ <libcamera/libcamera.h>\n\ \ \ \ #\ osnr:\ HACK:\ just\ throwing\ any\ possible\ path\ in.\n\ \ \ \ \$cpp\ cflags\ -I/usr/local/include/libcamera\ -I/usr/include/libcamera\n\ \ \ \ \$cpp\ endcflags\ -lcamera\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ using\ namespace\ libcamera\;\n\n\ \ \ \ \ \ \ \ std::unique_ptr<CameraManager>\ cm\;\n\ \ \ \ \ \ \ \ std::shared_ptr<Camera>\ camera\;\n\tstd::unique_ptr<CameraConfiguration>\ config\;\n\tFrameBufferAllocator\ *allocator\;\n\n\ \ \ \ \ \ \ \ //\ This\ vector\ always\ owns\ all\ the\ request\ objects.\n\tstd::vector<std::unique_ptr<Request>>\ requests\;\n\n\ \ \ \ \ \ \ \ std::mutex\ completedRequestsMutex\;\n\ \ \ \ \ \ \ \ std::queue<Request\ *>\ completedRequests\;\n\ \ \ \ \ \ \ \ std::condition_variable\ completedRequestsCv\;\n\n\ \ \ \ \ \ \ \ uint32_t\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ frameHeight\;\n\ \ \ \ \ \ \ \ uint32_t\ frameBytesPerRow\;\n\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ cameraOpen\ \{char*\ id\ int\ width\ int\ height\}\ void\ \{\n\ \ \ \ \ \ \ \ cm\ =\ std::make_unique<CameraManager>()\;\n\ \ \ \ \ \ \ \ cm->start()\;\n\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ cameras:\"\ <<\ std::endl\;\n\tfor\ (auto\ const\ &camera\ :\ cm->cameras())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"\ -\ \"\ <<\ camera->id()\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ camera\ =\ cm->get(id)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(camera\ !=\ nullptr)\;\n\ \ \ \ \ \ \ \ camera->acquire()\;\n\n\ \ \ \ \ \ \ \ config\ =\ camera->generateConfiguration(\{\ StreamRole::Viewfinder\ \})\;\n\ \ \ \ \ \ \ \ StreamConfiguration\ &streamConfig\ =\ config->at(0)\;\n\ \ \ \ \ \ \ \ streamConfig.size\ =\ Size(width,\ height)\;\n\ \ \ \ \ \ \ \ streamConfig.pixelFormat\ =\ PixelFormat::fromString(\"YUV420\")\;\n\n\ \ \ \ \ \ \ \ config->validate()\;\n\ \ \ \ \ \ \ \ frameWidth\ =\ streamConfig.size.width\;\n\ \ \ \ \ \ \ \ frameHeight\ =\ streamConfig.size.height\;\n\ \ \ \ \ \ \ \ frameBytesPerRow\ =\ streamConfig.stride\;\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"frameWidth:\ \"\ <<\ frameWidth\ <<\ \"\ frameHeight:\ \"\ <<\ frameHeight\ <<\ std::endl\;\n\n\tcamera->configure(config.get())\;\n\n\ \ \ \ \ \ \ \ allocator\ =\ new\ FrameBufferAllocator(camera)\;\n\tfor\ (StreamConfiguration\ &cfg\ :\ *config)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ allocator->allocate(cfg.stream())\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Can't\ allocate\ buffers\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ allocated\ =\ allocator->buffers(cfg.stream()).size()\;\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ Allocated\ \"\ <<\ allocated\ <<\ \"\ buffers\ for\ stream\"\ <<\ std::endl\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (PixelFormat\ &format\ :\ cfg.formats().pixelformats())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ std::cout\ <<\ \"camera/rpi:\ Stream\ supports\ format\ \"\ <<\ format\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (Size\ &size\ :\ cfg.formats().sizes(format))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ \ \ std::cout\ <<\ \"\ \ ->\ supports\ size\ \"\ <<\ size\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\t\}\n\n\ \ \ \ \ \ \ \ Stream\ *stream\ =\ streamConfig.stream()\;\n\ \ \ \ \ \ \ \ assert(streamConfig.pixelFormat.toString()\ ==\ \"YUV420\")\;\n\n\ \ \ \ \ \ \ \ const\ std::vector<std::unique_ptr<FrameBuffer>>\ &buffers\ =\ allocator->buffers(stream)\;\n\tfor\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ buffers.size()\;\ ++i)\ \{\n\t\tstd::unique_ptr<Request>\ request\ =\ camera->createRequest()\;\n\t\tif\ (!request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ create\ request\")\;\n\t\t\}\n\n\t\tconst\ std::unique_ptr<FrameBuffer>\ &buffer\ =\ buffers\[i\]\;\n\t\tint\ ret\ =\ request->addBuffer(stream,\ buffer.get())\;\n\t\tif\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ set\ buffer\ for\ request\")\;\n\t\t\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ControlList\ &controls\ =\ request->controls()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AeEnable,\ false)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::ExposureTime,\ 35000)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AfMode,\ controls::AfModeManual)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Focus\ 30cm\ away\ (0.3m\ ->\ 1/0.3\ =\ 3.3).\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::LensPosition,\ 1.6)\;\n\n\t\trequests.push_back(std::move(request))\;\n\t\}\n\n\tcamera->requestCompleted.connect(requestComplete)\;\n\n\ \ \ \ \ \ \ \ camera->start()\;\n\tfor\ (std::unique_ptr<Request>\ &request\ :\ requests)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(request.get())\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (request->status()\ ==\ Request::RequestCancelled)\ \{\n\t\treturn\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.lock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.push(request)\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.unlock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsCv.notify_one()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ static\ void\ processRequestAndCopyFrame(Request\ *request,\ Image\ im)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ Request::BufferMap\ &buffers\ =\ request->buffers()\;\n\ \ \ \ \ \ \ \ \ \ \ \ assert(buffers.size()\ ==\ 1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (auto\ bufferPair\ :\ buffers)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ (Unused)\ Stream\ *stream\ =\ bufferPair.first\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FrameBuffer\ *buffer\ =\ bufferPair.second\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ FrameMetadata\ &metadata\ =\ buffer->metadata()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(metadata.planes().size()\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(buffer->planes().size()\ ==\ 3)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto\ &plane\ =\ buffer->planes()\[0\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ fd\ =\ plane.fd.get()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *addr\ =\ mmap64(NULL,\ plane.length,\ PROT_READ,\ MAP_PRIVATE,\ fd,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (addr\ ==\ MAP_FAILED)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ MAP_FAILED\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *planeData\ =\ (uint8_t\ *)addr\ +\ plane.offset\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(im.data,\ planeData,\ frameHeight\ *\ frameBytesPerRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ munmap(addr,\ plane.length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ newImage\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ uint32_t\ width\ =\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ height\ =\ frameHeight\;\n\ \ \ \ \ \ \ \ int\ components\ =\ 1\;\n\ \ \ \ \ \ \ \ uint8_t\ *data\ =\ (uint8_t\ *)\ malloc(width*components*height)\;\n\ \ \ \ \ \ \ \ return\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ components,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ width*components,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ freeImage\ \{Image\ image\}\ void\ \{\n\ \ \ \ \ \ \ \ free(image.data)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ grayFrame\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ Request\ *latestRequest\ =\ nullptr\;\n\n\ \ \ \ \ \ \ \ //\ We\ want\ to\ drain\ the\ queue\ of\ completed\ requests.\n\ \ \ \ \ \ \ \ std::unique_lock\ lk(completedRequestsMutex)\;\n\ \ \ \ \ \ \ \ completedRequestsCv.wait(lk,\ \[\]\{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ !completedRequests.empty()\;\n\ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ while\ (!completedRequests.empty())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (latestRequest\ !=\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ We're\ skipping\ this\ request,\ because\ we\ have\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ newer\ one\ in\ the\ queue.\ Requeue\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ latestRequest\ =\ completedRequests.front()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.pop()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lk.unlock()\;\n\n\ \ \ \ \ \ \ \ if\ (latestRequest\ ==\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"No\ new\ frame\ yet\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ newImage()\;\n\ \ \ \ \ \ \ \ processRequestAndCopyFrame(latestRequest,\ im)\;\n\n\ \ \ \ \ \ \ \ /*\ Re-queue\ the\ Request\ to\ the\ camera.\ */\n\ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ compile\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /cameraPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/camera/rpi.folk}}
when {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ (
[ m783:0 (s1204:0 s1205:0) ]
)when {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
}
When /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
}
} with environment {{this builtin-programs/decorations/label.folk}}
when When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ (
[ m789:0 (s1214:0) ]
)when When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n\}\n with environment {{this builtin-programs/decorations/outline.folk}}
when When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/ (
[ m795:0 (s1223:0) ]
)when When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n\}\n with environment {{this builtin-programs/editor/draw-editor.folk}}
when {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport { (
[ m801:0 (s1232:0) ]
)when {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport {originalText x y width height} {
set lines [split $originalText \n]
set lines [lrange $lines $y [expr {($height - 1) + $y}]]
set lines [lmap line $lines {
set line [string range $line $x [expr {($width - 1) + $x}]]
}]
return [join $lines \n]
}
proc cursorToXy {code cursor} {
set codeBeforeCursor [string range $code 0 [- $cursor 1]]
set linesBeforeCursor [split $codeBeforeCursor "\n"]
set lineCountBeforeCursor [llength $linesBeforeCursor]
set cursorX [string length [lindex $linesBeforeCursor end]]
set cursorY [max [- $lineCountBeforeCursor 1] 0]
return [list $cursorX $cursorY]
}
proc xyToCursor {code cursorX cursorY} {
if { $cursorX < 0 } { set cursorX 0 }
if { $cursorY < 0 } { set cursorY 0 }
set lines [split $code "\n"]
set maxCursorY [max 0 [- [llength $lines] 1]]
set cursorY [min $cursorY $maxCursorY]
set relevantLines [lrange $lines 0 [- $cursorY 1]]
set relevantLineLen [string length [lindex $lines $cursorY]]
set joined [join $relevantLines "\n"]
# make sure cursorX < line length
set cursorX [min $cursorX $relevantLineLen]
set cursor [+ [string length $joined] $cursorX]
# don't forget to add the length of \n at the beginning
if {$cursorY > 0} { incr cursor }
return $cursor
}
proc insertText {code cursor newText} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code $cursor end]
set joined [join [list $before $newText $after] ""]
incr cursor
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $joined $cursor $maxCursorX]
}
proc deleteText {code cursor count} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code [+ $cursor $count] end]
set joined [join [list $before $after] ""]
return $joined
}
proc deleteToBeginning {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
set newLine [string range $line $x end]
lset lines $y $newLine
return [join $lines "\n"]
}
proc getLine {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
}
proc getLineLength {code cursor} {
set line [getLine $code $cursor]
set ll [string length $line]
return $ll
}
# returns {newCursor newMaxCursorX}
proc handleNavigation {key code cursor maxCursorX} {
switch $key {
Left {
set cursor [- $cursor 1]
set cursor [max $cursor 0]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Right {
set cursor [+ $cursor 1]
set codeLength [string length $code]
set cursor [min $cursor $codeLength]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Up {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [- $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Down {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [+ $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Control_a {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX 0
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
Control_e {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX [getLineLength $code $cursor]
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
}
return [list $cursor $maxCursorX]
}
# returns {newCode newCursor newMaxCursorX}
proc handleRemovalAndReturn {key code cursor maxCursorX} {
switch $key {
Delete {
if { $cursor != 0 } {
set cursor [- $cursor 1]
set code [deleteText $code $cursor 1]
set maxCursorX [lindex [cursorToXy $code $cursor] 0]
}
}
Remove {
set code [deleteText $code $cursor 1]
}
Control_u {
# delete from cursor back to 0 and move cursor to 0
lassign [cursorToXy $code $cursor] cursorX cursorY
set code [deleteToBeginning $code $cursor]
set newX 0
set cursor [xyToCursor $code $newX $cursorY]
}
Return {
# figure out how many spaces there are before the current line
regexp {^(\s*)} [getLine $code $cursor] -> spacing
set spacingLen [string length $spacing]
lassign [insertText $code $cursor "\n$spacing"] code
set maxCursorX $spacingLen
set cursor [+ $cursor [+ 1 $spacingLen]]
}
}
return [list $code $cursor $maxCursorX]
}
proc getSelectedText {code selAnchor cursor} {
set start [min $selAnchor $cursor]
set end [max $selAnchor $cursor]
return [string range $code $start [- $end 1]]
}
proc replaceRange {code rangeStart rangeEnd newText} {
if {$rangeStart > 0} {
set before [string range $code 0 [- $rangeStart 1]]
} else {
set before ""
}
set after [string range $code $rangeEnd end]
set code "${before}${newText}${after}"
set cursor [+ $rangeStart [string length $newText]]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $code $cursor $maxCursorX]
}
proc lineNumberView {ystart linecount} {
set yend [expr {$ystart + $linecount}]
set numbers [list]
for {set i [expr {$ystart + 1}]} {$i <= $yend} {incr i} {
lappend numbers $i
}
join $numbers "\n"
}
# For rendering:
proc getAdvance {em} {
# From NeomatrixCode.csv
return $(0.5859375 * $em)
}
proc widthAndHeight {resolvedGeom} {
set tagSize [dict get $resolvedGeom tagSize]
set left [dict get $resolvedGeom left]
set right [dict get $resolvedGeom right]
set top [dict get $resolvedGeom top]
set bottom [dict get $resolvedGeom bottom]
set width $($left + $tagSize + $right)
set height $($top + $tagSize + $bottom)
return [list $width $height]
}
# given program and the editor options, figure out how many characters can
# fit in this editor
proc editorSizeInCharacters {margin resolvedGeom options} {
set textScale [dict get $options scale]
set advance [getAdvance $textScale]
lassign [widthAndHeight $resolvedGeom] width height
set width $($width - [lindex $margin 3] - $advance*2.5 - [lindex $margin 1])
set height $($height - [lindex $margin 0] - [lindex $margin 2])
set widthInCharacters $(int($width / $advance))
set heightInCharacters $(int($height / $textScale))
return [list $widthInCharacters $heightInCharacters]
}
}]
} with environment {{this builtin-programs/editor/editor-utils.folk}}
when /editor/ is an editor with /...anything/ {When editor {$editor} has margin /margin/ & editor {$e ()when /editor/ is an editor with /...anything/ {When editor {$editor} has margin /margin/ & editor {$editor} has viewport position /vpPos/ & editor {$editor} has viewport size /vpSize/ & editor {$editor} has selected program /program/ & editor {$editor} on program /program/ has font options with /...fontOptions/ \n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n} with environment {{this builtin-programs/editor/draw-editor.folk} {} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {}}
when /editor/ is an editor with /...anything/ {When editor {$editor} has cursor /cursor/ & editor {$e ()when /editor/ is an editor with /...anything/ {When editor {$editor} has cursor /cursor/ & editor {$editor} has selected program /program/ & editor buffer for /program/ is /code/ & editor {$editor} has viewport position /vpPos/ & editor {$editor} on program /program/ has font options with /...textOptions/ {
lassign $vpPos vpX vpY
lassign [$utils cursorToXy $code $cursor] cursorX cursorY
set textScale [dict get $textOptions scale]
set advance [$utils getAdvance $textScale]
set offsetX $(($cursorX - $vpX) * $advance)
set offsetY $(($cursorY - $vpY) * $textScale)
Claim editor $editor has cursor position [list $offsetX $offsetY]
}} with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
when /editor/ is an editor with /...options/ \n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ ()when /editor/ is an editor with /...options/ \n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
when #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ lat (
[ m808:0 (s1242:0 s1243:0) ]
)when #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ later,\ or\ exclude\ keyboards\ that\ opt\ out.\nWhen\ /k/\ is\ a\ keyboard\ with\ /...opts/\ \{\n\ \ \ \ Wish\ tag\ \$k\ is\ stabilized\n\n\ \ \ \ When\ \$k\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ claims\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Create\ a\ synthetic\ editor\ on\ top\ of\ the\ program\ being\ edited,.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editor\ \[list\ \$k\ editor\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ is\ an\ editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ has\ a\ canvas\ with\ layer\ 98\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ has\ resolved\ geometry\ \$geom\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ quad\ /q/\ \{\ Claim\ \$editor\ has\ quad\ \$q\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ has\ created\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$editor\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$program\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ program\ save\ directory\ is\ /programDir/\ &\\\n\ \ \ \ \ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n\}\n with environment {{this builtin-programs/editor/editor.folk}}
when /k/ is a keyboard with /...opts/ {
Wish tag $k is stabilized
When $k points up with len ()when /k/ is a keyboard with /...opts/ {
Wish tag $k is stabilized
When $k points up with length 0.3 at /program/ {
When /nobody/ claims $program is an editor {
Wish tag $program is stabilized
# Create a synthetic editor on top of the program being edited,.
set editor [list $k editor]
Claim $editor is an editor
Claim editor $editor has selected program $program
Wish $editor has a canvas with layer 98
When $program has resolved geometry /geom/ {
Claim $editor has resolved geometry $geom
}
When $program has quad /q/ { Claim $editor has quad $q }
Claim $k has created editor $editor
Claim $k is typing into $editor
}
When $program is an editor {
Claim $k is typing into $program
}
}
} with environment {{this builtin-programs/editor/editor.folk} {} {}}
when fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ prog (
[ m814:0 (s1252:0 s1253:0) ]
)when fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\}\n\nSubscribe:\ print\ program\ from\ editor\ /editor/\ \{\n\ \ \ \ set\ options\ \[editorToPrintOptions\ \$editor\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\n\n#\ Print\ preview:\nWhen\ the\ codeToPostScript\ is\ /codeToPostScript/\ &\\\n\ \ \ \ \ /someone/\ wishes\ editor\ /editor/\ has\ a\ print\ preview\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/editor/print-editor.folk}}
when When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key (
[ m820:0 (s1262:0) ]
)when When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n\}\n with environment {{this builtin-programs/saving/save-programs.folk}}
when this is a first boot \n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\ ()when this is a first boot \n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n with environment {{this builtin-programs/saving/save-programs.folk} {} {}}
when set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\] (
[ m826:0 (s1271:0 s1272:0) ]
)when set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\]\}\ \{\n\ \ \ \ file\ mkdir\ \$dataDirectory\n\}\n\n#\ make\ sure\ the\ migration\ happens\ before\ loading\ everything,\n#\ so\ we\ load\ in\ the\ migrated\ data\nWhen\ the\ migration\ is\ complete\ \{\n\ \ \ \ set\ namespaces\ \[glob\ -nocomplain\ \$dataDirectory/*/\]\n\n\ \ \ \ foreach\ namespace\ \$namespaces\ \{\n\ \ \ \ \ \ \ \ set\ namespaceName\ \[file\ tail\ \$namespace\]\n\ \ \ \ \ \ \ \ Wish\ to\ deserialize\ namespace\ \$namespaceName\ with\ directory\ \$namespace\n\ \ \ \ \}\n\}\n\nWhen\ when\ the\ /fileType/\ save\ directory\ is\ /anything/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ set\ serdeDirectory\ \"\$dataDirectory/\$fileType\"\n\n\ \ \ \ #\ make\ sure\ directory\ exists\n\ \ \ \ file\ mkdir\ \$serdeDirectory\n\n\ \ \ \ Claim\ the\ \$fileType\ save\ directory\ is\ \$serdeDirectory\n\}\n with environment {{this builtin-programs/saving/saving.folk}}
when /keyboard/ is a keyboard with path /kbPath/ /...anything/ {When {$keyboard} is typing into /edit ()when /keyboard/ is a keyboard with path /kbPath/ /...anything/ {When {$keyboard} is typing into /editor/ & /editor/ is an editor with /...anything/ & editor /editor/ has selected program /program/ \n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
when /keyboard/ is a keyboard device \n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap (
[ m911:0 (s1678:0) ]
[ m944:0 (s2130:0) ]
[ m951:0 (s2249:0) ]
[ m952:0 (s2160:0) ]
)when /keyboard/ is a keyboard device \n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n with environment {{this builtin-programs/keyboard.folk} {} {keyboard /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd keyboardDevices {/dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd}}}
when /type/ /obj/ has a program \n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ (
[ m47938:640 (s15542:766 s15543:765) ]
[ m33923:727 (s14332:865 s14334:865) ]
[ m6500:990 (s53011:1175 s53015:1174) ]
[ m6661:984 (s53207:1171 s53209:1174 s53210:1174) ]
[ m3369:1022 (s32219:1211 s32220:1215) ]
[ m47701:1059 (s64455:1262 s64457:987 s64460:1258) ]
)when /type/ /obj/ has a program \n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ with environment {{saveDir /home/folk/folk-data/program} {}}
when When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ direct (
[ m837:0 (s1291:0) ]
)when When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /programDirectory/\ &\\\n\ \ \ \ \ saving\ is\ ready\ \{\n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n\}\n with environment {{this builtin-programs/saving/migrate.folk}}
when saving is ready \n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ (
[ m918:0 (s1563:0) ]
)when saving is ready \n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n with environment {{this builtin-programs/saving/migrate.folk} {} {} {holdDirectory /home/folk/folk-data/hold} {} {programDirectory /home/folk/folk-data/program} {}}
when set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h (
[ m847:0 (s1421:0 s1422:0) ]
)when set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ \"jim.h\"\n\n\$cc\ code\ \{\n\n/*\ Generic\ string\ hash\ function\ from\ jim.c\ */\nstatic\ unsigned\ int\ cacheGenHashFunction(const\ unsigned\ char\ *string,\ int\ length)\ \{\n\ \ \ \ unsigned\ result\ =\ 0\;\n\ \ \ \ string\ +=\ length\;\n\ \ \ \ while\ (length--)\ \{\n\ \ \ \ \ \ \ \ result\ +=\ (result\ <<\ 3)\ +\ (unsigned\ char)(*--string)\;\n\ \ \ \ \}\n\ \ \ \ return\ result\;\n\}\nstatic\ unsigned\ int\ holdHTHashFunction(const\ void\ *key)\ \{\n\ \ \ \ return\ cacheGenHashFunction(key,\ strlen(key))\;\n\}\nstatic\ void\ *holdHTKeyDup(void\ *privdata,\ const\ void\ *key)\ \{\n\ \ \ \ return\ strdup(key)\;\n\}\nstatic\ void\ *holdHTValDup(void\ *privdata,\ const\ void\ *val)\ \{\n\ \ \ \ return\ strdup(val)\;\n\}\nstatic\ int\ holdHTKeyCompare(void\ *privdata,\ const\ void\ *key1,\ const\ void\ *key2)\ \{\n\ \ \ \ return\ strcmp(key1,\ key2)\ ==\ 0\;\n\}\nstatic\ void\ holdHTKeyDestructor(void\ *privdata,\ void\ *key)\ \{\n\ \ \ \ free(key)\;\n\}\nstatic\ void\ holdHTValDestructor(void\ *privdata,\ void\ *val)\ \{\n\ \ \ \ free(val)\;\n\}\n\nstatic\ const\ Jim_HashTableType\ holdHashTableType\ =\ \{\n\ \ \ \ .hashFunction\ =\ holdHTHashFunction,\n\ \ \ \ .keyDup\ =\ holdHTKeyDup,\n\ \ \ \ .valDup\ =\ holdHTValDup,\n\ \ \ \ .keyCompare\ =\ holdHTKeyCompare,\n\ \ \ \ .keyDestructor\ =\ holdHTKeyDestructor,\n\ \ \ \ .valDestructor\ =\ holdHTValDestructor\n\}\;\n\n//\ key\ =\ value\ of\ -on\ passed\ to\ Hold!,\n//\ val\ =\ string\ that\ can\ be\ converted\ to\ a\ jim\ dict,\ with\n//\ that\ dict\ having\ its\ key\ =\ the\ value\ passed\ to\ -key\n//\ and\ its\ value\ =\ its\ corresponding\ held\ statement\nstatic\ Jim_HashTable\ holds\;\nstatic\ int\ areHoldsInitialized\ =\ 0\;\n\nstatic\ pthread_mutex_t\ holdMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ if\ (!areHoldsInitialized)\ \{\n\ \ \ \ \ \ \ \ areHoldsInitialized\ =\ 1\;\n\ \ \ \ \ \ \ \ Jim_InitHashTable(&holds,\ &holdHashTableType,\ interp)\;\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n\$cc\ proc\ loadHolds\ \{char*\ canonicalName\ char*\ holdStr\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonicalName,\ (void\ *)holdStr)\;\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n#\ canonical,\ tclEscaped,\ and\ filename\ all\ have\ to\ do\ with\ the\ value\ from\ -on\ in\ Hold!\n\$cc\ proc\ saveHold\ \{char*\ canonical\ Jim_Obj*\ tclEscaped\ char*\ filename\ Jim_Obj*\ key\ Jim_Obj*\ clause\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ assert(areHoldsInitialized)\;\n\n\ \ \ \ Jim_Obj*\ holdDict\ =\ NULL\;\n\n\ \ \ \ Jim_HashEntry*\ he\ =\ Jim_FindHashEntry(&holds,\ canonical)\;\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ //\ this\ is\ this\ files'\ first\ hold\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewStringObj(interp,\ (char\ *)Jim_GetHashEntryVal(he),\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ empty\ clause,\ e.g.\ removal\n\ \ \ \ if\ (Jim_Length(clause)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ NULL)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ clause)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonical,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_SetHashVal(&holds,\ he,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\n\ \ \ \ //\ grab\ entries\ from\ dict\n\ \ \ \ int\ dictLen\ =\ 0\;\n\ \ \ \ Jim_Obj**\ dictValues\ =\ Jim_DictPairs(interp,\ holdDict,\ &dictLen)\;\n\n\ \ \ \ if\ (dictLen\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ //\ write\ changes\n\ \ \ \ \ \ \ \ FILE*\ file\ =\ fopen(filename,\ \"w+b\")\;\n\ \ \ \ \ \ \ \ assert(file\ !=\ NULL)\;\n\n\ \ \ \ \ \ \ \ //\ write\ the\ filename\ in\ tcl\ form\ at\ the\ top\ of\ the\ file\n\ \ \ \ \ \ \ \ fwrite(Jim_String(tclEscaped),\ 1,\ Jim_Length(tclEscaped),\ file)\;\n\ \ \ \ \ \ \ \ fwrite(\"\\n\\n\",\ 1,\ 2,\ file)\;\n\n\ \ \ \ \ \ \ \ //\ write\ all\ hash\ entries,\ with\ one\ entry\ per\ line\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ dictLen\;\ i\ +=\ 2)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ pair\[\]\ =\ \{\ dictValues\[i\],\ dictValues\[i\ +\ 1\]\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ tmpListObj\ =\ Jim_NewListObj(interp,\ pair,\ 2)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(Jim_String(tmpListObj),\ 1,\ Jim_Length(tmpListObj),\ file)\;\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(\"\\n\",\ 1,\ 1,\ file)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_FreeNewObj(interp,\ tmpListObj)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ fclose(file)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ //\ the\ dict\ is\ empty,\ so\ we\ should\ delete\ its\ hold\ file\ if\ it\ exists\n\ \ \ \ \ \ \ \ remove(filename)\;\ //\ no\ need\ to\ check\ error\n\ \ \ \ \}\n\n\ \ \ \ Jim_FreeNewObj(interp,\ holdDict)\;\n\}\n\nset\ savedHoldsLib\ \[\$cc\ compile\]\n\$savedHoldsLib\ init\n\nWhen\ /someone/\ wishes\ to\ deserialize\ namespace\ hold\ with\ directory\ /directory/\ \{\n\ \ \ \ set\ holdFiles\ \[glob\ -nocomplain\ \$directory/*\]\n\n\ \ \ \ foreach\ holdFile\ \$holdFiles\ \{\n\ \ \ \ \ \ \ \ set\ fd\ \[open\ \$holdFile\ r\]\n\ \ \ \ \ \ \ \ set\ holds\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ #\ the\ hold\ file's\ first\ line\ is\ its\ canonical\ name\ (since\n\ \ \ \ \ \ \ \ #\ having\ /\ in\ a\ filename\ would\ mess\ a\ lot\ of\ stuff\ up),\n\ \ \ \ \ \ \ \ #\ while\ the\ rest\ of\ the\ file\ is\ a\ dict\ of\ holds\n\ \ \ \ \ \ \ \ set\ canonicalName\ \[lindex\ \$holds\ 0\]\n\ \ \ \ \ \ \ \ set\ holdDict\ \[lrange\ \$holds\ 1\ end\]\n\n\ \ \ \ \ \ \ \ dict\ for\ \{key\ clause\}\ \$holdDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ \$canonicalName\ -key\ \$key\ --\ \{*\}\$clause\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ loadHolds\ \$canonicalName\ \$holdDict\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ saved\ holds\ are\ loaded\n\}\n\nWhen\ the\ hold\ save\ directory\ is\ /holdDirectory/\ \{\n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n\}\n with environment {{this builtin-programs/saving/save-holds.folk}}
when {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
floa (
[ m855:0 (s1315:0 s1316:0 s1317:0) ]
)when {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
Wish the GPU compiles function "wedge2d" {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
# See https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/
Wish the GPU compiles function "invBilinear" {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
} with environment {{this builtin-programs/gpu/gpu-fns.folk}}
when #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ (
[ m861:0 (s1326:0 s1327:0 s1328:0) ]
)when #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ used\ to\ create\ sensitive\ areas\ other\ pages\ can\ collect.\nWhen\ /someone/\ wishes\ /p/\ adds\ region\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ region\ /r/\ has\ highlight\ /highlighted/\ with\ /...options/\ \{\n\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\n\ \ if\ \{\$highlighted\}\ \{\n\ \ \ \ set\ verts\ \[region\ vertices\ \$r\]\n\ \ \ \ set\ edges\ \[region\ edges\ \$r\]\n\ \ \ \ lappend\ verts\ \[lindex\ \$verts\ 0\]\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$verts\ color\ \$color\ width\ \$thickness\ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n\}\n with environment {{this builtin-programs/shapes/region.folk}}
when #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ (
[ m867:0 (s1337:0 s1338:0) ]
)when #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n#\ \ \ \ \ Wish\ to\ draw\ an\ arc\ with\ x\ \$x\ y\ \$y\ start\ 0\ arclen\ 1\ thickness\ 3\ radius\ 100\ color\ green\n#\ \ \ \}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"arc\"\ \{\{vec2\ center\ float\ start\ float\ arclen\ float\ radius\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\ \ \ \ \ \ \ \ \ center\ +\ r\n\ \ \ \ )\;\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\}\ \{\n\ \ \ \ #define\ M_TWO_PI\ 6.283185307179586\n\ \ \ \ start\ =\ clamp(start,\ 0,\ M_TWO_PI)\;\n\ \ \ \ arclen\ =\ clamp(arclen,\ 0,\ M_TWO_PI)\;\n\n\ \ \ \ float\ dist\ =\ length(gl_FragCoord.xy\ -\ center)\ -\ radius\;\n\ \ \ \ float\ angle\ =\ atan(-(gl_FragCoord.y\ -\ center.y),\ gl_FragCoord.x\ -\ center.x)\;\n\n\ \ \ \ //\ Shift\ angle\ from\ \[-pi,\ pi)\ to\ \[0,\ 2*pi\]\n\ \ \ \ angle\ =\ (angle\ <\ 0)\ ?\ (angle\ +\ M_TWO_PI)\ :\ angle\;\n\ \ \ \ float\ end\ =\ start\ +\ arclen\;\n\n\ \ \ \ return\ ((dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((end\ <\ M_TWO_PI\ &&\ angle\ >\ start\ &&\ angle\ <\ end)\ ||\ \n\ \ \ \ \ \ \ \ \ \ \ \ (end\ >=\ M_TWO_PI\ &&\ (angle\ >\ start\ ||\ angle\ <\ end-M_TWO_PI))))\ ?\ color\ :\ vec4(0,\ 0,\ 0,\ 0)\;\n\n\}\}\n\nWhen\ /someone/\ wishes\ to\ draw\ an\ arc\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/display/arc.folk}}
when \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ comp (
[ m873:0 (s1347:0 s1348:0 s1349:0 s1350:0 s1351:0) ]
)when \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ compiles\ function\ \"bboxBezier\"\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\}\ vec4\ \{\n\ \ \ \ //\ Exact\ BBox\ to\ a\ quadratic\ bezier\n\ \ \ \ //\ extremes\n\ \ \ \ vec2\ mi\ =\ min(p0,p3)\;\n\ \ \ \ vec2\ ma\ =\ max(p0,p3)\;\n\n\ \ \ \ vec2\ k0\ =\ -1.0*p0\ +\ 1.0*p1\;\n\ \ \ \ vec2\ k1\ =\ \ 1.0*p0\ -\ 2.0*p1\ +\ 1.0*p2\;\n\ \ \ \ vec2\ k2\ =\ -1.0*p0\ +\ 3.0*p1\ -\ 3.0*p2\ +\ 1.0*p3\;\n\n\ \ \ \ vec2\ h\ =\ k1*k1\ -\ k0*k2\;\n\n\ \ \ \ if(\ h.x>0.0\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.x\ =\ sqrt(h.x)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.x\ -\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.x/(-k1.x-h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.x\ +\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ t\ =\ k0.x/(-k1.x+h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if(\ h.y>0.0)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.y\ =\ sqrt(h.y)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.y\ -\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.y/(-k1.y-h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.y\ +\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ t\ =\ k0.y/(-k1.y+h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \n\ \ \ \ return\ vec4(\ mi,\ ma\ )\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ sdSegmentSq\ \{\{vec2\ p\ vec2\ a\ vec2\ b\}\ float\ \{\n\ \ \ \ vec2\ pa\ =\ p-a,\ ba\ =\ b-a\;\n\ \ \ \ float\ h\ =\ clamp(\ dot(pa,ba)/dot(ba,ba),\ 0.0,\ 1.0\ )\;\n\ \ \ \ vec2\ d\ =\ pa\ -\ ba*h\;\n\ \ \ \ return\ dot(d,\ d)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ udBezier\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ vec2\ pos\}\ vec2\ \{\n\ \ \ \ const\ int\ kNum\ =\ 50\;\n\ \ \ \ vec2\ res\ =\ vec2(1e10,0.0)\;\n\ \ \ \ vec2\ a\ =\ p0\;\n\ \ \ \ for(\ int\ i=1\;\ i<kNum\;\ i++\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ float\ t\ =\ float(i)/float(kNum-1)\;\n\ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ vec2\ b\ =\ p0*s*s*s\ +\ p1*3.0*s*s*t\ +\ p2*3.0*s*t*t\ +\ p3*t*t*t\;\n\ \ \ \ \ \ \ \ float\ d\ =\ sdSegmentSq(\ pos,\ a,\ b\ )\;\n\ \ \ \ \ \ \ \ if(\ d<res.x\ )\ res\ =\ vec2(d,t)\;\n\ \ \ \ \ \ \ \ a\ =\ b\;\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ vec2(sqrt(res.x),res.y)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"curve\"\ \{\n\ \ \{\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ //\ Need\ to\ calculate\ the\ bounds\ of\ the\ curve\n\ \ \ \ vec2\ from\ =\ min(min(p0,p1),min(p2,p3))\;\n\ \ \ \ vec2\ to\ =\ max(max(p0,p1),max(p2,p3))\;\n\ \ \ \ \n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ min(from,\ to)\ -\ thickness,\n\ \ \ \ \ \ vec2(max(from.x,\ to.x)\ +\ thickness,\ min(from.y,\ to.y)\ -\ thickness),\n\ \ \ \ \ \ vec2(min(from.x,\ to.x)\ -\ thickness,\ max(from.y,\ to.y)\ +\ thickness),\n\ \ \ \ \ \ max(from,\ to)\ +\ thickness\n\ \ \ \ )\;\n\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\ \ \}\ \{fn\ sdSegmentSq\ fn\ udBezier\}\ \{\n\ \ \ \ vec2\ p\ =\ gl_FragCoord.xy\;\n\ \ \ \ float\ px\ =\ 2.0\;\ //\ sharpness\n\ \ \ \ float\ t\ =\ thickness\;\n\ \ \ \ float\ be\ =\ udBezier(\ p0,\ p1,\ p2,\ p3,\ p\ ).x\;\n\n\ \ \ \ float\ d\ =\ be\;\n\n\ \ \ \ vec4\ col\ =\ mix(\ vec4(0.0),\ color,\ 1.0-smoothstep(t,\ t\ +\ px*1.5,\ d)\ )\;\n\n\ \ \ \ //\ control\ points\n\ \ \ \ //d\ =\ length(p0-p)\;\ col\ =\ mix(\ col,\ vec4(1.0,\ 0.,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p1-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 1.0,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p2-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 0.,\ 1.0,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p3-p)\;\ col\ =\ mix(\ col,\ vec4(1.0),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\n\ \ \ \ return\ col\;\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ curve\ with\ /...options/\ \{\n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n with environment {{this builtin-programs/display/curve.folk}}
when When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ (
[ m879:0 (s1360:0 s1361:0) ]
)when When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ TrOCR\ text\ recognizer\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ TrOCR\ text\ recognizer\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ transformers\ --with\ pillow\ --with\ torch\ --with\ protobuf\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ from\ transformers\ import\ TrOCRProcessor,\ VisionEncoderDecoderModel\n\ \ \ \ \ \ \ \ import\ os\n\ \ \ \ \ \ \ \ import\ sys\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ #\ Determine\ device\ (prefer\ CUDA\ >\ MPS\ >\ CPU)\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ #\ Load\ TrOCR\ model\n\ \ \ \ \ \ \ \ TROCR_PATH\ =\ os.path.expanduser(\"~/folk-data/trocr\")\n\ \ \ \ \ \ \ \ try:\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ disk.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ except\ Exception:\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Model\ not\ saved\;\ loading\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ processor.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ model.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ model.to(device)\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ ocrImage\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ start_time\ =\ time.time()\n\n\ \ \ \ \ \ \ \ #\ Run\ TrOCR\ on\ the\ entire\ image\n\ \ \ \ \ \ \ \ with\ torch.no_grad():\n\ \ \ \ \ \ \ \ \ \ \ \ pixel_values\ =\ processor(image,\ return_tensors=\"pt\").pixel_values.to(device)\n\ \ \ \ \ \ \ \ \ \ \ \ generated_ids\ =\ model.generate(pixel_values)\n\ \ \ \ \ \ \ \ \ \ \ \ text\ =\ processor.batch_decode(generated_ids,\ skip_special_tokens=True)\[0\]\n\n\ \ \ \ \ \ \ \ elapsed\ =\ time.time()\ -\ start_time\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Result:\ \{text\}\ (\{elapsed:.3f\}s)\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ return\ text\n\ \ \ \ \}\n\n\ \ \ \ fn\ TrOCR\ \{im\}\ \{\ return\ \[\$py\ ocrImage\ \$im\]\ \}\n\ \ \ \ Claim\ the\ TrOCR\ text\ recognizer\ is\ \[fn\ TrOCR\]\n\}\n\n with environment {{this builtin-programs/recognition/trocr.folk}}
when When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ (
[ m885:0 (s1370:0 s1371:0) ]
)when When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ SAM2\ segmenter\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ SAM2\ segmenter\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n\}\n\n with environment {{this builtin-programs/recognition/sam2.folk}}
when When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ (
[ m891:0 (s1380:0 s1381:0) ]
)when When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ CRAFT\ text\ detector\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ CRAFT\ text\ detector\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ \"git+https://github.com/osnr/craft-text-detector.git\"\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ from\ craft_text_detector\ import\ Craft\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ craft\ =\ Craft(output_dir=None,\ crop_type=\"box\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ link_threshold=0.1,\ device=device)\n\ \ \ \ \}\n\ \ \ \ \$py\ def\ detectTextBoxes\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image)\n\n\ \ \ \ \ \ \ \ start_craft\ =\ time.time()\n\ \ \ \ \ \ \ \ result\ =\ craft.detect_text(image_np)\n\ \ \ \ \ \ \ \ boxes\ =\ result\[\"boxes\"\]\n\ \ \ \ \ \ \ \ craft_time\ =\ time.time()\ -\ start_craft\n\n\ \ \ \ \ \ \ \ print(f\"craft:\ Detected\ \{len(boxes)\}\ text\ boxes\ (\{craft_time:.3f\}s)\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ return\ boxes.tolist()\ if\ hasattr(boxes,\ 'tolist')\ else\ boxes\n\ \ \ \ \}\n\n\ \ \ \ fn\ CRAFT\ \{im\}\ \{\ return\ \[\$py\ detectTextBoxes\ \$im\]\ \}\n\ \ \ \ Claim\ the\ CRAFT\ text\ detector\ is\ \[fn\ CRAFT\]\n\}\n\n with environment {{this builtin-programs/recognition/craft.folk}}
when When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$i (
[ m897:0 (s1390:0 s1391:0 s1392:0) ]
)when When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ cflags\ -I.\n\ \ \ \ \$cc\ include\ \"vendor/CContour.c\"\n\n\ \ \ \ #\ Binarizes\ the\ first\ channel\ of\ `im`\ at\ `threshold`\ and\ returns\n\ \ \ \ #\ the\ contours\ as\ a\ Tcl\ list.\ Each\ contour\ is\ itself\ a\ Tcl\ list\ of\n\ \ \ \ #\ \{x\ y\}\ pairs.\ If\ epsilon\ >\ 0,\ each\ contour\ is\ simplified\ with\n\ \ \ \ #\ Ramer-Douglas-Peucker.\n\ \ \ \ #\n\ \ \ \ #\ Contours\ are\ scaled\ by\ `scaleX`\ and\ `scaleY`\ so\ that\ they\ can\ be\n\ \ \ \ #\ returned\ in\ real-world\ meters\ (instead\ of\ image-pixel\ space).\n\ \ \ \ #\n\ \ \ \ #\ Discards\ any\ contours\ that\ are\ not\ at\ least\ minLength\ long\n\ \ \ \ #\ (unless\ minLength\ is\ very\ small).\n\ \ \ \ \$cc\ proc\ findImageContours\ \{Image\ im\ int\ threshold\ double\ epsilon\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ scaleX\ double\ scaleY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ minLength\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ w\ =\ (int)im.width\;\n\ \ \ \ \ \ \ \ int\ h\ =\ (int)im.height\;\n\ \ \ \ \ \ \ \ if\ (w\ <\ 3\ ||\ h\ <\ 3)\ return\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ int\ *F\ =\ malloc(sizeof(int)\ *\ (size_t)w\ *\ (size_t)h)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ h\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ *row\ =\ im.data\ +\ (size_t)y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ *Frow\ =\ F\ +\ (size_t)y\ *\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ w\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Frow\[x\]\ =\ (row\[x\ *\ im.components\]\ >\ threshold)\ ?\ 1\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Contour\ *contours\ =\ findContours(F,\ w,\ h)\;\n\ \ \ \ \ \ \ \ free(F)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj\ *outer\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (ptrdiff_t\ c\ =\ 0\;\ c\ <\ arrlen(contours)\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Point\ *pts\ =\ (epsilon\ >\ 0)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ?\ approxPolyDP(contours\[c\].points,\ (float)epsilon)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :\ contours\[c\].points\;\n\ \ \ \ \ \ \ \ \ \ \ \ ptrdiff_t\ n\ =\ arrlen(pts)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (minLength\ >\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ total\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 1\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ (pts\[k\].x\ -\ pts\[k-1\].x)\ *\ scaleX\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ (pts\[k\].y\ -\ pts\[k-1\].y)\ *\ scaleY\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (total\ <\ minLength)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ %g\ prints\ up\ to\ ~13\ chars\ per\ double\;\ round\ up\ to\ give\ headroom.\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ cap\ =\ (size_t)n\ *\ 40\ +\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ char\ *buf\ =\ malloc(cap)\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ off\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 0\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ off\ +=\ snprintf(buf\ +\ off,\ cap\ -\ off,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\ ==\ 0\ ?\ \"\{%g\ %g\}\"\ :\ \"\ \{%g\ %g\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pts\[k\].x\ *\ scaleX,\ pts\[k\].y\ *\ scaleY)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Jim_NewStringObjNoAlloc\ takes\ ownership\ of\ buf.\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ outer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObjNoAlloc(interp,\ buf,\ (int)off))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ freeContours(contours)\;\n\ \ \ \ \ \ \ \ return\ outer\;\n\ \ \ \ \}\n\n\ \ \ \ set\ contourLib\ \[\$cc\ compile\]\n\ \ \ \ Claim\ the\ contour\ library\ is\ \$contourLib\n\}\n\nWhen\ /someone/\ wishes\ /p/\ has\ contours\ \{\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ _\ \{\}\n\}\nWhen\ the\ contour\ library\ is\ /contourLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ contours\ with\ /...opts/\ \{\n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n\}\n with environment {{this builtin-programs/recognition/contours.folk}}
when {Wish $::thisNode uses display "monitor" with width 1920 height 1200 refreshRate 60000} with env (
[ m933:0 (s1615:0) ]
)when {Wish $::thisNode uses display "monitor" with width 1920 height 1200 refreshRate 60000} with environment {}
when {Wish $::thisNode uses camera "/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0" wit (
[ m932:0 (s1614:0) ]
)when {Wish $::thisNode uses camera "/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0" with width 1920 height 1080 framerate 60.0} with environment {}
when {Wish $::thisNode uses display "monitor" with width 4096 height 2160 refreshRate 60000} with env (
[ m931:0 (s1613:0) ]
)when {Wish $::thisNode uses display "monitor" with width 4096 height 2160 refreshRate 60000} with environment {}
when {
Wish camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposu (
[ m930:0 (s1612:0) ]
)when {
Wish camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposure time 6800 us
} with environment {}
when {
When $program has program code /originalCode/ {
Cl (
[ m929:0 (s1611:0) ]
)when {
When $program has program code /originalCode/ {
Claim editor buffer for $program is $originalCode
}
} with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_xw0Gqn.tcl>} {defaults { textScale 0.01 }} {keyboard 49 kbPath /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd anything {locale us}} {} {editor {49 editor}} {} {anything {textScale 0.01}} {} {program 12} {} {key Control_r keyState down options {timestamp 1781548580.45}} {isUndo false origCode {Wish $this displays image "https://blob.gifcities.org/gifcities/OVXJ222ZMQPYSF4W3EY5TX7O6B43P5JH.gif"
Wish $this is outlined bluesr} lastEditType {} redoStack {} code {Wish $this displays image "https://blob.gifcities.org/gifcities/OVXJ222ZMQPYSF4W3EY5TX7O6B43P5JH.gif"
Wish $this is outlined bluesr} origMaxCursorX 28 vpWidth 42 vpY 0 vpHeight 16 vpSize {42 16} clipboard {} isNavKey 0 undoStack {} selectionHandled false cursor 0 selAnchor {} vpPos {0 0} hasShift 0 resetBuffer true isRedo false textOptions {scale 0.00751314800902} maxCursorX 0 origCursor 132 vpX 0}}
when 12 has program code /originalCode/ {
Claim editor buffer for $program is ()when 12 has program code /originalCode/ {
Claim editor buffer for $program is $originalCode
} with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_xw0Gqn.tcl>} {defaults { textScale 0.01 }} {keyboard 49 kbPath /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd anything {locale us}} {} {editor {49 editor}} {} {anything {textScale 0.01}} {} {program 12} {} {key Control_r keyState down options {timestamp 1781548580.45}} {isUndo false origCode {Wish $this displays image "https://blob.gifcities.org/gifcities/OVXJ222ZMQPYSF4W3EY5TX7O6B43P5JH.gif"
Wish $this is outlined bluesr} lastEditType {} redoStack {} code {Wish $this displays image "https://blob.gifcities.org/gifcities/OVXJ222ZMQPYSF4W3EY5TX7O6B43P5JH.gif"
Wish $this is outlined bluesr} origMaxCursorX 28 vpWidth 42 vpY 0 vpHeight 16 vpSize {42 16} clipboard {} isNavKey 0 undoStack {} selectionHandled false cursor 0 selAnchor {} vpPos {0 0} hasShift 0 resetBuffer true isRedo false textOptions {scale 0.00751314800902} maxCursorX 0 origCursor 132 vpX 0} {} {}}
when /tag/ has resolved geometry /geom/ {When tag {$tag} has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$ (
[ m25749:914 (s2891:1084) ]
[ m6744:990 (s53309:1175) ]
[ m3084:1024 (s31877:1215) ]
[ m44677:1037 (s51878:1228) ]
[ m65106:1056 () ]
[ m23380:1039 (s14726:1259) ]
[ m23387:1039 (s14731:1255) ]
[ m23397:1062 (s14742:1258) ]
[ m23402:1062 (s14748:1222) ]
[ m23408:1062 (s14754:1256) ]
[ m23414:1062 (s14760:1223) ]
[ m23426:1062 (s14773:1219) ]
[ m23434:1062 (s14780:1223) ]
[ m47788:1063 (s64557:1258) ]
)when /tag/ has resolved geometry /geom/ {When tag {$tag} has quad /q/ \n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n} with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>}}
when /tag/ has canvas /writableTextureId/ with /...wiOptions/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ # (
[ m23651:0 (s31335:0) ]
[ m25667:915 (s2802:1088) ]
[ m6673:985 (s53228:1173) ]
[ m6692:989 (s53250:1174) ]
[ m3062:1023 (s31851:1214) ]
[ m37496:1029 () ]
[ m44647:1033 (s51855:1233) ]
[ m24838:1043 () ]
[ m64902:1056 () ]
[ m65098:1057 () ]
[ m23353:1039 (s14685:1260) ]
[ m47729:1060 (s64499:1262) ]
)when /tag/ has canvas /writableTextureId/ with /...wiOptions/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {}}
when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ (
[ m33947:727 () ]
[ m55301:735 () ]
[ m46387:776 () ]
[ m60165:887 () ]
[ m25747:915 () ]
)when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {} {p 11 impath https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif} {}}
when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ (
[ m33955:727 () ]
[ m55295:735 () ]
[ m46378:775 () ]
[ m60159:888 () ]
[ m25738:915 (s2881:1088) ]
)when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {} {p 11 impath https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif options {scale 1.0}} {}}
when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ ()when 11 has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {} {p 11 impath {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} options {scale 1.0}} {}}
when 11 has resolved geometry /geom/ {
set frames [dict get $gif frames]
set delays [dic (
[ m25744:915 (s2886:1087) ]
)when 11 has resolved geometry /geom/ {
set frames [dict get $gif frames]
set delays [dict get $gif delays]
set totalDuration 0
set cumulativeDelays [list]
foreach d $delays {
if {$d <= 10} { set d 100 }
incr totalDuration $d
lappend cumulativeDelays $totalDuration
}
if {[llength $frames] == 0} { return }
if {[llength $frames] == 1} {
Wish $p displays image [lindex $frames 0] with {*}$options
return
}
When the clock time is /t/ {
set ms [expr {int($t * 1000) % $totalDuration}]
set frameIdx 0
foreach cd $cumulativeDelays {
if {$ms < $cd} { break }
incr frameIdx
}
if {$frameIdx >= [llength $frames]} { set frameIdx 0 }
set im [lindex $frames $frameIdx]
Wish $p displays image $im with {*}$options
}
} with environment {{this builtin-programs/draw/gif.folk} {} {} {gifLib <C:cfiled3kiwc>} {} {p 11 gif {frames {{width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0346e20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03558a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b035cde0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0364320}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b036b860}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0372da0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b037a2e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0381820}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0388d60}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03902a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03977e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b039ed20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03a6260}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03ad7a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03b4ce0}}} delays {250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250} width 100 height 100} options {scale 1.0}} {}}
when 11 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m27629:1067 () ]
[ m28006:1066 () ]
[ m28346:1067 () ]
[ m28791:1066 () ]
[ m28805:1066 () ]
[ m28965:1063 () ]
[ m29555:1066 () ]
[ m29683:1062 (s11813:1265) ]
)when 11 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{11\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 11 writableTextureId {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m25672:915 (s2806:1088) ]
)when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 11 writableTexture {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {}}
when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m25687:915 (s2822:1087) ]
)when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {}}
when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m25692:912 (s2829:1086) ]
)when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {}}
when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m25698:911 (s2835:1088) ]
)when 11 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 11 id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {}}
when 11 has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\ ()when 11 has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 11 options {image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} position {0 0} anchor topleft width 0.100666666667}} {} {id {11 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}}} {}}
when 11 has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\n\ \ ()when 11 has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 11 options {image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} position {0 0} anchor topleft width 0.100666666667}} {}}
when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$ (
[ m23601:0 (s31267:0) ]
)when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p monitor writableTexture {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto (
[ m23603:0 (s31269:0) ]
)when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} wi (
[ m23605:0 (s31271:0) ]
)when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} (
[ m23607:0 (s31273:0) ]
)when monitor has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ (
[ m6786:1066 (s38755:1263 s38756:1263) ]
)when monitor has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {p0 {2770.94576434 1140.12894428} p1 {2769.84476267 1367.39171626} p2 {2530.60087726 1399.3331699} p3 {2539.32201432 1175.33046251} color black layer 100}} {} {id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ ()when monitor has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {p0 {1775.27099448 247.242764445} p1 {1959.53096269 234.542121022} p2 {1971.33498788 419.234334367} p3 {1786.93461061 432.701559053} color black layer 100}} {} {id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas projection /surfaceToClip/ {When the GPU has font PTSans-Regular with data /f (
[ m51786:1064 (s16240:1262) ]
)when monitor has canvas projection /surfaceToClip/ {When the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ } with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {position {2896.19187753 1020.39598124} scale 36.0 radians -1.56722363723 anchor bottom text {(edited Fri, 08 May 2026, 09:00 PM)}}} {radians -1.56722363723 x0 2896.19187753 y0 1020.39598124 anchor {0.5 1 0.5 1} layer 0 text {(edited Fri, 08 May 2026, 09:00 PM)} font PTSans-Regular scale 36.0 color {1.0 1.0 1.0 1.0}} {id {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {}}
when monitor has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\ (
[ m6782:1066 (s38751:1263) ]
)when monitor has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {p0 {2770.94576434 1140.12894428} p1 {2769.84476267 1367.39171626} p2 {2530.60087726 1399.3331699} p3 {2539.32201432 1175.33046251} color black layer 100}} {}}
when monitor has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\ ()when monitor has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/fill.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {p0 {1775.27099448 247.242764445} p1 {1959.53096269 234.542121022} p2 {1971.33498788 419.234334367} p3 {1786.93461061 432.701559053} color black layer 100}} {}}
when monitor has canvas /id/ with /...wiOptions/ {When monitor has canvas projection /surfaceToClip/ (
[ m51780:1064 (s16237:1262) ]
)when monitor has canvas /id/ with /...wiOptions/ {When monitor has canvas projection /surfaceToClip/ & the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ } with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p monitor options {position {2896.19187753 1020.39598124} scale 36.0 radians -1.56722363723 anchor bottom text {(edited Fri, 08 May 2026, 09:00 PM)}}} {radians -1.56722363723 x0 2896.19187753 y0 1020.39598124 anchor {0.5 1 0.5 1} layer 0 text {(edited Fri, 08 May 2026, 09:00 PM)} font PTSans-Regular scale 36.0 color {1.0 1.0 1.0 1.0}}}
when monitor has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ ()when monitor has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{monitor\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag monitor writableTextureId {monitor canvas} wiOptions {width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 63 has camera slice /slice/ {__setFreshAtomicallyVersionOnKey {63 {63 1} {63 has camera slice /s (
[ m3379:1021 (s32231:1215) ]
[ m29054:1066 () ]
[ m29096:1067 () ]
[ m29247:1067 () ]
[ m29339:1062 () ]
[ m29598:1067 (s11692:1266) ]
)when 63 has camera slice /slice/ {__setFreshAtomicallyVersionOnKey {63 {63 1} {63 has camera slice /slice/}};
Wish $this displays camera slice $slice
} with environment {{this 63} {} {}}
when 63 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m28217:1066 () ]
[ m28399:1067 () ]
[ m28580:1067 () ]
[ m28679:1067 () ]
[ m29070:1066 () ]
[ m29269:1066 () ]
[ m29618:1067 (s11719:1265) ]
)when 63 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{63\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 63 writableTextureId {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m44658:1033 (s51860:1230) ]
)when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 63 writableTexture {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {}}
when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m44664:1039 (s51863:1228) ]
)when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {}}
when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m44668:1038 (s51868:1213) ]
)when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {}}
when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m44675:1039 (s51875:1233) ]
)when 63 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 63 id {63 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}}} {}}
when {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 4
} with environmen (
[ m47962:643 (s15571:766 s15572:766) ]
)when {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 4
} with environment {{this 62}}
when {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXP (
[ m33943:727 (s14353:860) ]
)when {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
} with environment {{this 11}}
when 54-display has resolved geometry /geom/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ ge (
[ m6680:988 () ]
[ m11001:1002 () ]
[ m37604:1029 () ]
[ m23420:1040 (s14767:1255) ]
)when 54-display has resolved geometry /geom/ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this builtin-programs/gpu/canvases.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {pipelineLib <C:cfilekUErd7>} {} {gpuTextureLib <C:cfileHQKyt3>} {gpuc ::<reference.<C______>.00000000000000000010> gpuCanvasLib <C:cfile8rArAA>} {p 54-display options {settle 0ms width 1024 height 1024}} {pCanvas {54-display canvas}} {canvOpts {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-display has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-display color white} {}}
when 54-display has resolved geometry /geom/ {When the animation toy's fps is /FPS/ & the animation t ()when 54-display has resolved geometry /geom/ {When the animation toy's fps is /FPS/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {}}
when 54-display has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ ()when 54-display has resolved geometry /geom/ \n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {loadImage {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}} {} {p 54-display impath {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}} options {width 0.1055}} {}}
when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto (
[ m6697:990 () ]
[ m11014:1000 () ]
[ m37610:1026 () ]
[ m23424:1062 (s14772:1256) ]
)when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 54-display writableTexture {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line on (
[ m6700:988 () ]
[ m11013:1003 () ]
[ m37609:1033 () ]
[ m23423:1040 (s14771:1222) ]
)when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} (
[ m6704:990 () ]
[ m11010:1003 () ]
[ m37608:1023 () ]
[ m23422:1062 (s14769:1259) ]
)when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$ (
[ m6708:990 () ]
[ m11002:1004 () ]
[ m37605:1033 () ]
[ m23421:1040 (s14768:1256) ]
)when 54-display has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54-display id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ im ()when 54-display has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 54-display options {image {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}} position {0 0} anchor topleft width 0.1055}} {} {id {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {}}
when 54-display has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ ()when 54-display has canvas /id/ with /...wiOptions/ {When {$p} has canvas projection /surfaceToClip/ \n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n} with environment {{this builtin-programs/draw/image.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {p 54-display options {image {width {95} height {62} components {3} bytesPerRow {285} uniq {-781439560} data {(uint8_t*) 0x79cd13e6ca80}} position {0 0} anchor topleft width 0.1055}} {}}
when 54-display has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.fo (
[ m7505:1064 () ]
[ m19413:1064 () ]
[ m21975:962 () ]
[ m24061:1064 () ]
[ m28765:1065 () ]
[ m29158:1065 () ]
[ m29448:1065 () ]
[ m31289:1034 () ]
[ m34899:1064 () ]
[ m46656:1065 () ]
[ m46836:1065 () ]
[ m46943:1062 () ]
[ m47210:1065 () ]
[ m47500:1064 () ]
[ m47881:1065 () ]
[ m48090:1065 () ]
[ m48304:1062 () ]
[ m48629:1064 () ]
[ m48695:1064 () ]
[ m49038:1064 () ]
[ m49151:1063 () ]
[ m49348:1061 () ]
[ m49592:1064 () ]
[ m49887:1065 () ]
[ m50138:1065 () ]
[ m50354:1064 () ]
[ m50600:1053 () ]
[ m50792:1064 () ]
[ m50862:1063 () ]
[ m51164:1064 () ]
[ m51285:1057 () ]
[ m51592:1065 () ]
[ m51807:1065 () ]
[ m53524:1063 (s16265:1264) ]
[ m54838:1051 (s16265:1264) ]
[ m58982:1065 (s16265:1264) ]
[ m64900:1065 (s16265:1264) ]
[ m1116:1066 (s16265:1264) ]
[ m6630:1048 (s16265:1264) ]
[ m29399:1065 (s16265:1264) ]
[ m29848:1066 (s16265:1264) ]
[ m34480:1066 (s16265:1264) ]
[ m44676:1064 (s16265:1264) ]
[ m45690:1065 (s16265:1264) ]
[ m57021:1066 (s16265:1264) ]
[ m58396:1066 (s16265:1264) ]
[ m61210:1065 (s16265:1264) ]
[ m62767:1060 (s16265:1264) ]
[ m65435:1065 (s16265:1264) ]
[ m4604:1067 (s16265:1264) ]
[ m14250:1067 (s16265:1264) ]
[ m23132:1066 (s16265:1264) ]
[ m23492:1066 (s16265:1264) ]
[ m23988:1064 (s16265:1264) ]
[ m26485:1067 (s16265:1264) ]
[ m26871:1067 (s16265:1264) ]
[ m27035:1064 (s16265:1264) ]
[ m27409:1065 (s16265:1264) ]
[ m27555:1067 (s16265:1264) ]
[ m27724:1065 (s16265:1264) ]
[ m28070:1065 (s16265:1264) ]
[ m28301:1067 (s16265:1264) ]
[ m28717:1065 (s16265:1264) ]
[ m29051:1065 (s16265:1264) ]
[ m29329:1060 (s16265:1264) ]
[ m29621:1049 (s16265:1264) ]
[ m29792:1061 (s16265:1264) ]
)when 54-display has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{54-display\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 54-display writableTextureId {54-display canvas} wiOptions {settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this (
[ m6519:990 (s53035:1174 s53036:1174 s53037:1174 s53040:1174 s53041:1174 s53043:1175) ]
)when set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n with environment {{this 54}}
when 54 has quad /q/ {When 54-display has resolved geometry /geom/ & the animation toy's fps is /FPS/ (
[ m29334:1065 () ]
[ m29626:1066 () ]
[ m29797:1066 () ]
)when 54 has quad /q/ {When 54-display has resolved geometry /geom/ & the animation toy's fps is /FPS/ & the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when 54 has quad /q/ {
set displayQuad [$quadLib scale $q 50%]
set displayQuad [$quadLib move (
[ m28054:1067 () ]
[ m28289:1051 () ]
[ m28390:1058 () ]
[ m28710:1050 () ]
[ m29044:1063 () ]
[ m29315:1066 () ]
[ m29611:1065 () ]
[ m29782:1061 () ]
)when 54 has quad /q/ {
set displayQuad [$quadLib scale $q 50%]
set displayQuad [$quadLib move $displayQuad up 60% right 160%]
Claim -keep 10ms $this-display has quad $displayQuad
Wish -keep 10ms $this-display is outlined white
} with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {}}
when 54 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{54\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ ()when 54 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{54\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 54} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top} {results {{text {(edited Fri, 08 May 2026, 09:00 PM)}}}} {text {(edited Fri, 08 May 2026, 09:00 PM)} result {text {(edited Fri, 08 May 2026, 09:00 PM)}}}}
when 54 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m51970:1065 (s16215:1251) ]
[ m52339:1060 (s16215:1251) ]
[ m52394:1065 (s16215:1251) ]
[ m52672:1059 (s16215:1251) ]
[ m52996:1065 (s16215:1251) ]
[ m53095:1061 (s16215:1251) ]
[ m53492:1062 (s16215:1251) ]
[ m53747:1063 (s16215:1251) ]
[ m54050:1065 (s16215:1251) ]
[ m54315:1049 (s16215:1251) ]
[ m54813:1065 (s16215:1251) ]
[ m55202:1062 (s16215:1251) ]
[ m55407:1061 (s16215:1251) ]
[ m55609:1061 (s16215:1251) ]
[ m55938:1063 (s16215:1251) ]
[ m56168:1064 (s16215:1251) ]
[ m56356:1065 (s16215:1251) ]
[ m56564:1064 (s16215:1251) ]
[ m56626:1057 (s16215:1251) ]
[ m57008:1065 (s16215:1251) ]
[ m58947:1064 (s16215:1251) ]
[ m59321:1065 (s16215:1251) ]
[ m59599:1062 (s16215:1251) ]
[ m59712:1065 (s16215:1251) ]
[ m61114:1065 (s16215:1251) ]
[ m62053:1061 (s16215:1251) ]
[ m62356:1062 (s16215:1251) ]
[ m62442:1053 (s16215:1251) ]
[ m63529:1065 (s16215:1251) ]
[ m63776:1064 (s16215:1251) ]
[ m64262:1065 (s16215:1251) ]
[ m64544:1062 (s16215:1251) ]
[ m64869:1064 (s16215:1251) ]
[ m65028:1064 (s16215:1251) ]
[ m1102:1066 (s16215:1251) ]
[ m1206:1064 (s16215:1251) ]
[ m2603:1066 (s16215:1251) ]
[ m3297:1065 (s16215:1251) ]
[ m3978:1065 (s16215:1251) ]
[ m5346:1018 (s16215:1251) ]
[ m6058:1065 (s16215:1251) ]
[ m6341:1066 (s16215:1251) ]
[ m6605:1049 (s16215:1251) ]
[ m7062:1063 (s16215:1251) ]
[ m7565:1063 (s16215:1251) ]
[ m7865:1066 (s16215:1251) ]
[ m7987:1066 (s16215:1251) ]
[ m8300:1064 (s16215:1251) ]
[ m9258:1066 (s16215:1251) ]
[ m9490:1066 (s16215:1251) ]
[ m10380:1064 (s16215:1251) ]
[ m10904:1040 (s16215:1251) ]
[ m11167:1064 (s16215:1251) ]
[ m11472:1066 (s16215:1251) ]
[ m11903:1063 (s16215:1251) ]
[ m12321:1064 (s16215:1251) ]
[ m14038:1066 (s16215:1251) ]
[ m14793:1066 (s16215:1251) ]
[ m15246:1065 (s16215:1251) ]
[ m15502:1066 (s16215:1251) ]
[ m15859:1065 (s16215:1251) ]
[ m16283:1066 (s16215:1251) ]
[ m16760:1065 (s16215:1251) ]
[ m18366:1056 (s16215:1251) ]
[ m19308:1053 (s16215:1251) ]
[ m19851:1065 (s16215:1251) ]
[ m19964:1062 (s16215:1251) ]
[ m20209:1066 (s16215:1251) ]
[ m20530:1066 (s16215:1251) ]
[ m20639:1066 (s16215:1251) ]
[ m20957:1050 (s16215:1251) ]
[ m21288:1066 (s16215:1251) ]
[ m21359:1066 (s16215:1251) ]
[ m21614:1065 (s16215:1251) ]
[ m21863:1061 (s16215:1251) ]
[ m22085:991 (s16215:1251) ]
[ m22219:1066 (s16215:1251) ]
[ m22917:1066 (s16215:1251) ]
[ m23186:1065 (s16215:1251) ]
[ m23589:1066 (s16215:1251) ]
[ m24115:1066 (s16215:1251) ]
[ m24494:1066 (s16215:1251) ]
[ m24860:1062 (s16215:1251) ]
[ m26356:1066 (s16215:1251) ]
[ m26670:1064 (s16215:1251) ]
[ m26985:1066 (s16215:1251) ]
[ m27154:1066 (s16215:1251) ]
[ m27457:1061 (s16215:1251) ]
[ m27953:1050 (s16215:1251) ]
[ m29017:1065 (s16215:1251) ]
[ m29356:1064 (s16215:1251) ]
[ m29818:1065 (s16215:1251) ]
[ m29890:1066 (s16215:1251) ]
[ m31195:1064 (s16215:1251) ]
[ m31481:1066 (s16215:1251) ]
[ m31661:1056 (s16215:1251) ]
[ m31898:1066 (s16215:1251) ]
[ m32087:1065 (s16215:1251) ]
[ m32439:1066 (s16215:1251) ]
[ m32886:1064 (s16215:1251) ]
[ m33022:1066 (s16215:1251) ]
[ m33265:1066 (s16215:1251) ]
[ m33460:1066 (s16215:1251) ]
[ m33725:1066 (s16215:1251) ]
[ m33898:1065 (s16215:1251) ]
[ m34125:1061 (s16215:1251) ]
[ m34353:1066 (s16215:1251) ]
[ m34434:1064 (s16215:1251) ]
[ m35260:1053 (s16215:1251) ]
[ m36050:1063 (s16215:1251) ]
[ m36297:1066 (s16215:1251) ]
[ m36567:1066 (s16215:1251) ]
[ m36864:1064 (s16215:1251) ]
[ m36930:1061 (s16215:1251) ]
[ m37110:1066 (s16215:1251) ]
[ m38046:1064 (s16215:1251) ]
[ m38562:1038 (s16215:1251) ]
[ m39932:1066 (s16215:1251) ]
[ m40215:1066 (s16215:1251) ]
[ m40480:1066 (s16215:1251) ]
[ m40840:1065 (s16215:1251) ]
[ m41004:1066 (s16215:1251) ]
[ m41162:1060 (s16215:1251) ]
[ m41815:1066 (s16215:1251) ]
[ m41966:1066 (s16215:1251) ]
[ m43217:1064 (s16215:1251) ]
[ m43506:1061 (s16215:1251) ]
[ m43621:1066 (s16215:1251) ]
[ m44133:1055 (s16215:1251) ]
[ m44306:1056 (s16215:1251) ]
[ m44634:1063 (s16215:1251) ]
[ m44820:1066 (s16215:1251) ]
[ m45068:1065 (s16215:1251) ]
[ m45189:1066 (s16215:1251) ]
[ m45660:1065 (s16215:1251) ]
[ m45956:1033 (s16215:1251) ]
[ m46267:1065 (s16215:1251) ]
[ m46418:1066 (s16215:1251) ]
[ m46705:1065 (s16215:1251) ]
[ m46939:1066 (s16215:1251) ]
[ m47270:1065 (s16215:1251) ]
[ m47661:1065 (s16215:1251) ]
[ m48138:1066 (s16215:1251) ]
[ m48500:1066 (s16215:1251) ]
[ m48655:1065 (s16215:1251) ]
[ m48906:1064 (s16215:1251) ]
[ m49087:1062 (s16215:1251) ]
[ m49511:1065 (s16215:1251) ]
[ m49782:1063 (s16215:1251) ]
[ m50132:1066 (s16215:1251) ]
[ m50410:1064 (s16215:1251) ]
[ m50740:1063 (s16215:1251) ]
[ m50983:1063 (s16215:1251) ]
[ m51734:1066 (s16215:1251) ]
[ m53493:1052 (s16215:1251) ]
[ m54243:1066 (s16215:1251) ]
[ m54431:1065 (s16215:1251) ]
[ m55177:1064 (s16215:1251) ]
[ m55509:1065 (s16215:1251) ]
[ m56579:1066 (s16215:1251) ]
[ m56978:1066 (s16215:1251) ]
[ m57534:1066 (s16215:1251) ]
[ m57692:1066 (s16215:1251) ]
[ m57962:1065 (s16215:1251) ]
[ m58368:1066 (s16215:1251) ]
[ m58701:1066 (s16215:1251) ]
[ m58759:1066 (s16215:1251) ]
[ m59029:1065 (s16215:1251) ]
[ m59302:1066 (s16215:1251) ]
[ m59540:1065 (s16215:1251) ]
[ m59767:1066 (s16215:1251) ]
[ m60013:1066 (s16215:1251) ]
[ m60113:1066 (s16215:1251) ]
[ m60352:1066 (s16215:1251) ]
[ m60642:1058 (s16215:1251) ]
[ m60877:1066 (s16215:1251) ]
[ m61181:1064 (s16215:1251) ]
[ m61717:1063 (s16215:1251) ]
[ m62334:1066 (s16215:1251) ]
[ m62734:1013 (s16215:1251) ]
[ m62954:1066 (s16215:1251) ]
[ m63706:1065 (s16215:1251) ]
[ m63968:1066 (s16215:1251) ]
[ m64394:1065 (s16215:1251) ]
[ m64688:1066 (s16215:1251) ]
[ m64836:1066 (s16215:1251) ]
[ m65135:1063 (s16215:1251) ]
[ m65416:1064 (s16215:1251) ]
[ m65515:1065 (s16215:1251) ]
[ m577:1067 (s16215:1251) ]
[ m2358:1066 (s16215:1251) ]
[ m3304:1067 (s16215:1251) ]
[ m3857:1035 (s16215:1251) ]
[ m4119:1067 (s16215:1251) ]
[ m4573:1058 (s16215:1251) ]
[ m4672:1066 (s16215:1251) ]
[ m4812:1065 (s16215:1251) ]
[ m5149:1004 (s16215:1251) ]
[ m5456:1066 (s16215:1251) ]
[ m5785:1064 (s16215:1251) ]
[ m5928:1067 (s16215:1251) ]
[ m6163:1065 (s16215:1251) ]
[ m7516:1067 (s16215:1251) ]
[ m7821:1066 (s16215:1251) ]
[ m8135:1067 (s16215:1251) ]
[ m8254:1067 (s16215:1251) ]
[ m8549:1067 (s16215:1251) ]
[ m8815:1067 (s16215:1251) ]
[ m8887:806 (s16215:1251) ]
[ m9163:1066 (s16215:1251) ]
[ m9484:1067 (s16215:1251) ]
[ m9625:1067 (s16215:1251) ]
[ m9929:1065 (s16215:1251) ]
[ m10063:1065 (s16215:1251) ]
[ m10535:1066 (s16215:1251) ]
[ m10864:1041 (s16215:1251) ]
[ m10953:1041 (s16215:1251) ]
[ m11470:1067 (s16215:1251) ]
[ m12128:1065 (s16215:1251) ]
[ m12415:1067 (s16215:1251) ]
[ m12582:1067 (s16215:1251) ]
[ m12845:1066 (s16215:1251) ]
[ m13313:1067 (s16215:1251) ]
[ m13998:1067 (s16215:1251) ]
[ m14230:1067 (s16215:1251) ]
[ m14362:1066 (s16215:1251) ]
[ m14662:1065 (s16215:1251) ]
[ m14795:1066 (s16215:1251) ]
[ m15025:1066 (s16215:1251) ]
[ m16112:877 (s16215:1251) ]
[ m16681:1067 (s16215:1251) ]
[ m16790:1067 (s16215:1251) ]
[ m17101:1064 (s16215:1251) ]
[ m17379:1057 (s16215:1251) ]
[ m17581:1066 (s16215:1251) ]
[ m18711:1067 (s16215:1251) ]
[ m19252:1065 (s16215:1251) ]
[ m19419:1064 (s16215:1251) ]
[ m20726:1061 (s16215:1251) ]
[ m21260:1067 (s16215:1251) ]
[ m21600:1067 (s16215:1251) ]
[ m22456:1065 (s16215:1251) ]
[ m22638:1066 (s16215:1251) ]
[ m22805:1065 (s16215:1251) ]
[ m23075:1052 (s16215:1251) ]
[ m23114:1066 (s16215:1251) ]
[ m23439:1066 (s16215:1251) ]
[ m23948:1067 (s16215:1251) ]
[ m24174:1066 (s16215:1251) ]
[ m24747:1065 (s16215:1251) ]
[ m24796:1059 (s16215:1251) ]
[ m25037:1055 (s16215:1251) ]
[ m25272:1067 (s16215:1251) ]
[ m25524:1066 (s16215:1251) ]
[ m25768:1066 (s16215:1251) ]
[ m25999:1067 (s16215:1251) ]
[ m26381:1067 (s16215:1251) ]
[ m26466:1066 (s16215:1251) ]
[ m26852:1066 (s16215:1251) ]
[ m27021:1067 (s16215:1251) ]
[ m27397:1066 (s16215:1251) ]
[ m27533:1067 (s16215:1251) ]
[ m27706:1052 (s16215:1251) ]
[ m28052:1067 (s16215:1251) ]
[ m28280:1060 (s16215:1251) ]
[ m28385:1067 (s16215:1251) ]
[ m28708:1048 (s16215:1251) ]
[ m29043:1067 (s16215:1251) ]
[ m29304:1066 (s16215:1251) ]
[ m29606:1067 (s16215:1251) ]
[ m29780:1056 (s16215:1251) ]
[ m30040:1063 (s16215:1251) ]
)when 54 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{54\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 54 writableTextureId {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 54 has resolved geometry /geom/ {When the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ (
[ m6548:967 () ]
[ m10902:1007 () ]
[ m37526:1032 () ]
[ m23375:1039 (s14707:1259) ]
)when 54 has resolved geometry /geom/ {When the animation toy's frame count is /N_FRAMES/ \n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n} with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {}}
when 54 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[l (
[ m6757:972 () ]
[ m10897:1007 () ]
[ m37522:1033 () ]
[ m23371:1040 (s14702:1260) ]
)when 54 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54 color green} {}}
when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m23358:1058 (s14687:1260) ]
)when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 54 writableTexture {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {}}
when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m23360:1059 (s14689:1260) ]
)when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {}}
when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m23362:1038 (s14691:1260) ]
)when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {}}
when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m23364:1040 (s14694:1260) ]
)when 54 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {}}
when 54 has canvas projection /surfaceToClip/ {When the GPU has font PTSans-Regular with data /fontDa ()when 54 has canvas projection /surfaceToClip/ {When the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ } with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 options {x 0.1055 y 0.0995 scale 0.02 font PTSans-Regular text {FPS: 4
Frame count: 6}}} {radians 0 x0 0.1055 y0 0.0995 anchor {0.5 0.5 0.5 0.5} layer 0 text {FPS: 4
Frame count: 6} font PTSans-Regular scale 0.02 color {1.0 1.0 1.0 1.0}} {id {54 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}}} {}}
when 54 has canvas /id/ with /...wiOptions/ {When 54 has canvas projection /surfaceToClip/ & the GPU ()when 54 has canvas /id/ with /...wiOptions/ {When 54 has canvas projection /surfaceToClip/ & the GPU has font PTSans-Regular with data /fontData/ \n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ } with environment {{this builtin-programs/draw/text.folk} {} {} {imageLib <C:cfileV8MUaU>} {fontLib <C:cfileJp5g7P> cc ::<reference.<C______>.00000000000000000002>} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 54 options {x 0.1055 y 0.0995 scale 0.02 font PTSans-Regular text {FPS: 4
Frame count: 6}}} {radians 0 x0 0.1055 y0 0.0995 anchor {0.5 0.5 0.5 0.5} layer 0 text {FPS: 4
Frame count: 6} font PTSans-Regular scale 0.02 color {1.0 1.0 1.0 1.0}}}
when 82 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m29733:1067 () ]
[ m29874:1052 () ]
[ m29966:1056 (s12136:1266) ]
)when 82 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{82\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 82 writableTextureId {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m6725:990 (s53286:1175) ]
)when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 82 writableTexture {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {}}
when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m6731:990 (s53294:1175) ]
)when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {}}
when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m6737:978 (s53301:1172) ]
)when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {}}
when 82 has canvas projection /surfaceToClip/ {When /p/ is a viewport \n\n\ \ \ \ set\ wiResolution\ (
[ m6740:990 (s53302:1175) ]
)when 82 has canvas projection /surfaceToClip/ {When /p/ is a viewport \n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n} with environment {{this 82} {} {} {id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {}}
when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m6743:978 (s53305:1175) ]
)when 82 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 82 id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {}}
when 82 has canvas /id/ with /...wiOptions/ {When 82 has canvas projection /surfaceToClip/ & /p/ is a (
[ m6736:978 (s53300:1175) ]
)when 82 has canvas /id/ with /...wiOptions/ {When 82 has canvas projection /surfaceToClip/ & /p/ is a viewport \n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n} with environment {{this 82} {} {}}
when 82 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[l (
[ m47736:1064 (s64501:1262) ]
)when 82 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 82 color red} {}}
when When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ proje (
[ m6734:979 (s53296:1175) ]
)when When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n with environment {{this 82}}
when 62 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m29018:1066 () ]
[ m29218:1062 () ]
[ m29550:1067 () ]
[ m29775:1057 () ]
[ m29917:1067 () ]
[ m30007:1067 (s12184:1265) ]
)when 62 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{62\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 62 writableTextureId {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 62 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{62\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ (
[ m28918:1067 () ]
[ m28997:1067 () ]
[ m29199:1067 () ]
[ m29537:1060 () ]
[ m29755:1067 () ]
[ m29905:1067 () ]
[ m29994:1059 (s12170:1264) ]
)when 62 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{62\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 62} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top} {results {{text {(edited Fri, 08 May 2026, 10:10 PM)}}}} {text {(edited Fri, 08 May 2026, 10:10 PM)} result {text {(edited Fri, 08 May 2026, 10:10 PM)}}}}
when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m3072:1023 (s31859:1214) ]
)when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 62 writableTexture {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {}}
when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m3075:1024 (s31866:1215) ]
)when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {}}
when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m3079:1024 (s31869:1203) ]
)when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {}}
when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m3081:1024 (s31874:1215) ]
)when 62 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 62 id {62 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}}} {}}
when {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
} with enviro (
[ m3378:1022 (s32230:1205) ]
)when {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
} with environment {{this 63}}
when 83 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[l (
[ m47730:1060 (s64493:1262) ]
)when 83 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 83 color white} {}}
when 83 has resolved geometry /geom/ {When 83 has camera slice /s/ \n\ \ \ \ \ \ \ \ set\ scaleX\ \[/ (
[ m47748:1060 (s64514:1262) ]
)when 83 has resolved geometry /geom/ {When 83 has camera slice /s/ \n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ } with environment {{this builtin-programs/recognition/contours.folk} {} {} {contourLib <C:cfileQnzeGL>} {} {p 83 opts {threshold 28 epsilon 3.0 minLength 0.01}} {}}
when 83 has contours /cs/ with /...any/ \n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs (
[ m29490:1066 () ]
[ m29544:1067 () ]
[ m29654:1066 () ]
[ m29740:1065 () ]
[ m29785:1062 () ]
[ m29916:1065 (s12077:1260 s12084:1265) ]
)when 83 has contours /cs/ with /...any/ \n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ with environment {{this 82} {} {} {id {82 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}}} {} {surfaceToClip {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}} {} {p 83} {scale 0.5 wiResolution {1024 1024} palette {{1 0 0 1} {0 1 0 1} {0 0 1 1} {1 1 0 1}
{1 0 1 1} {0 1 1 1} {1 0.5 0 1} {1 1 1 1}}}}
when 83 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{bu (
[ m29702:1067 () ]
[ m29843:1067 (s11997:1261) ]
)when 83 has quad /quad/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/tags-to-quads.folk\ \{builtin-programs/tags-to-quads.folk\ 769\}\ \{83\ has\ quad\ /quad/\}\}\;\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ with environment {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} quadLib <library:/tmp/quadLib_K8EENR.tcl> poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {tag 83 writableTextureId {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {displayToClip {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}}}
when 83 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{83\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ (
[ m28851:1067 () ]
[ m28926:1067 () ]
[ m29279:1065 () ]
[ m29453:1067 () ]
[ m29690:1065 () ]
[ m29822:1065 (s11974:1261) ]
)when 83 has quad /q/ __setFreshAtomicallyVersionOnKey\ \{83\ quad\ titled\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ with environment {{this builtin-programs/title.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {thing 83} {label titled ^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} textAnchor bottom edge top} {results {{text {(edited Mon, 15 Jun 2026, 06:30 PM)}}}} {text {(edited Mon, 15 Jun 2026, 06:30 PM)} result {text {(edited Mon, 15 Jun 2026, 06:30 PM)}}}}
when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} wi (
[ m47739:1060 (s64505:1262) ]
)when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw an AprilTag onto {$p} with /...options/ \n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n} with environment {{this builtin-programs/draw/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {} {printLib <C:cfileDzXJHE>} {} {p 83 writableTexture {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {}}
when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} (
[ m47746:1060 (s64512:1262) ]
)when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a dashed line onto {$p} with /...options/ \n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/dashed-line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {}}
when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /. (
[ m47754:1064 (s64519:1258) ]
)when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a line onto {$p} with /...options/ \n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n} with environment {{this builtin-programs/draw/line.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {}}
when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with (
[ m47770:1062 (s64536:1258) ]
)when 83 has canvas projection /surfaceToClip/ {When /someone/ wishes to draw a circle onto {$p} with /...options/ \n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n} with environment {{this builtin-programs/draw/circle.folk} {} {} {colorMap {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}} {} {p 83 id {83 canvas} wiOptions {width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}}} {}}
when 83 has camera slice /s/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/recognition/contour (
[ m47750:1059 (s64517:1262) ]
[ m29408:1067 () ]
[ m29487:1066 () ]
[ m29540:1067 () ]
[ m29650:1067 () ]
[ m29737:1065 () ]
[ m29781:1058 () ]
[ m29913:1067 (s12076:1263) ]
)when 83 has camera slice /s/ __setFreshAtomicallyVersionOnKey\ \{builtin-programs/recognition/contours.folk\ \{builtin-programs/recognition/contours.folk\ 86\}\ \{83\ has\ camera\ slice\ /s/\}\}\;\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ with environment {{this builtin-programs/recognition/contours.folk} {} {} {contourLib <C:cfileQnzeGL>} {} {p 83 opts {threshold 28 epsilon 3.0 minLength 0.01}} {} {geom {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}} {}}
when {Claim $this is a viewport
Wish $this is outlined white} with environment {{this 83}} (
[ m47723:1061 (s64486:1262 s64488:1262) ]
)when {Claim $this is a viewport
Wish $this is outlined white} with environment {{this 83}}
when 54-frame-5 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-5 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 5 frameGeom {width 0.1055 height 0.0695}} {color red} {}}
when 54-frame-5 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-5 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-5 color red} {}}
when 54-frame-5 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-5 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 1 col 1 i 5 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0376754600542 -0.25228167737 0.700700360345} {-0.0315547948092 -0.309297558753 0.673893332779} {0.00510265543677 -0.314395607899 0.693106121133} {-0.00101800981423 -0.257379726517 0.719913148709}}}}}
when 54-frame-4 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-4 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 1 col 0 i 4 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0437961253023 -0.195265795986 0.727507387917} {-0.0376754600573 -0.252281677369 0.700700360351} {-0.00101800981133 -0.257379726515 0.719913148705} {-0.00713867506233 -0.200363845133 0.746720176281}}}}}
when 54-frame-4 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-4 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 4 frameGeom {width 0.1055 height 0.0695}} {color green} {}}
when 54-frame-4 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-4 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-4 color green} {}}
when 54-frame-6 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-6 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 6 frameGeom {width 0.1055 height 0.0695}} {color red} {}}
when 54-frame-6 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-6 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-6 color red} {}}
when 54-frame-6 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-6 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 1 col 2 i 6 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0315547948061 -0.309297558753 0.673893332774} {-0.0254341295611 -0.366313440136 0.647086305208} {0.0112233206849 -0.371411489282 0.666299093562} {0.00510265543387 -0.3143956079 0.693106121138}}}}}
when 54-frame-1 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-1 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 1 frameGeom {width 0.1055 height 0.0695}} {color red} {}}
when 54-frame-1 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-1 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-1 color red} {}}
when 54-frame-1 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-1 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 0 i 1 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0804535755455 -0.190167746839 0.708294599558} {-0.0743329103005 -0.247183628222 0.681487571992} {-0.0376754600545 -0.252281677368 0.700700360346} {-0.0437961253055 -0.195265795986 0.727507387922}}}}}
when 54-frame-2 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-2 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 2 frameGeom {width 0.1055 height 0.0695}} {color red} {}}
when 54-frame-2 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-2 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-2 color red} {}}
when 54-frame-2 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-2 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 1 i 2 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0743329102974 -0.247183628223 0.681487571986} {-0.0682122450524 -0.304199509606 0.65468054442} {-0.0315547948064 -0.309297558752 0.673893332774} {-0.0376754600574 -0.25228167737 0.70070036035}}}}}
when 54-frame-3 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ ()when 54-frame-3 has camera slice /slice/ \n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.255023324278 0.0344307682062 0.723853046399} {-0.234621106789 -0.155622169737 0.634496287836} {-0.112429605973 -0.17261566689 0.698538915692} {-0.13283182347 0.0174372710486 0.787895674271}}}} {} {geom {width 0.1055 height 0.0695}} {} {FPS 4} {} {N_FRAMES 6} {row 0 col 2 i 3 frameQuad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.0682122450493 -0.304199509606 0.654680544415} {-0.0620915798043 -0.361215390989 0.627873516849} {-0.0254341295583 -0.366313440135 0.647086305203} {-0.0315547948093 -0.309297558753 0.673893332779}}}}}
when 54-frame-3 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frame ()when 54-frame-3 has quad /frameQuad/ \n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ with environment {{this 54} {} {COLS 3} {disp monitor displayWidth 4096 displayHeight 2160} {} {displayIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {} {poseLib <C:cfile03l1Md>} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {geom {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}} {} {N_FRAMES 6} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} i 3 frameGeom {width 0.1055 height 0.0695}} {color red} {}}
when 54-frame-3 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ poi ()when 54-frame-3 has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing 54-frame-3 color red} {}}
when builtin-programs/terminal-ui.folk has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ ()when builtin-programs/terminal-ui.folk has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing builtin-programs/terminal-ui.folk color white} {}}
when builtin-programs/terminal.folk has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ ()when builtin-programs/terminal.folk has resolved geometry /geom/ \n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n with environment {{this builtin-programs/decorations/outline.folk} {} {} {thing builtin-programs/terminal.folk color white} {}}
when __setFreshAtomicallyVersionOnKey\ \{54\ quad\}\;\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ ()when __setFreshAtomicallyVersionOnKey\ \{54\ quad\}\;\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ with environment {{this builtin-programs/mask-tags.folk} {} {} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {poseLib <C:cfile03l1Md>} {} {quadChange {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}} {} {proj monitor projWidth 4096 projHeight 2160} {} {projectorIntrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}} {^quadChange {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}}} {id 54 q {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.214050418859 -0.10524634153 0.673727942539} {-0.211149629643 -0.132268086262 0.661023190136} {-0.18477736328 -0.135935747518 0.674845340033} {-0.187678152497 -0.108914002786 0.687550092437}}}} {}}
<unknown> claims builtin-programs/points-at.folk has program code When\ when\ /rect/\ points\ /direct (
[ m1:0 (s6:0) ]
)<unknown> claims builtin-programs/points-at.folk has program code When\ when\ /rect/\ points\ /direction/\ with\ length\ /l/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ \$l\n\}\n\nWhen\ when\ /rect/\ points\ /direction/\ at\ /someone/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ if\ \{\[string\ match\ \"/*\"\ \$rect\]\}\ \{\ return\ \}\n\ \ Wish\ \$rect\ points\ \$direction\ with\ length\ 1\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /rect/\ points\ /direction/\ with\ length\ /l/\ \{\n\nWhen\ \$rect\ has\ quad\ /quad/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\n\ \ \ \ fn\ quadChange\n\ \ \ \ set\ scale\ \$l\n\n\ \ \ \ set\ quad\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$quad\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ up\ \[scale\ \$scale\ \[sub\ \$topCenter\ \$bottomCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$topCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$topCenter\ \$up\]\n\ \ \ \ \ \ \ \ set\ color\ blue\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ left\ \[scale\ \$scale\ \[sub\ \$leftCenter\ \$rightCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$leftCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$leftCenter\ \$left\]\n\ \ \ \ \ \ \ \ set\ color\ gold\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ leftCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ rightCenter\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ right\ \[scale\ \$scale\ \[sub\ \$rightCenter\ \$leftCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$rightCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$rightCenter\ \$right\]\n\ \ \ \ \ \ \ \ set\ color\ red\n\n\ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ set\ topCenter\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ set\ bottomCenter\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ set\ down\ \[scale\ \$scale\ \[sub\ \$bottomCenter\ \$topCenter\]\]\n\n\ \ \ \ \ \ \ \ set\ from\ \$bottomCenter\n\ \ \ \ \ \ \ \ set\ to\ \[add\ \$bottomCenter\ \$down\]\n\ \ \ \ \ \ \ \ set\ color\ white\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"points-at:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ This\ implementation\ is\ sort\ of\ inelegant\ in\ that\ it\n\ \ \ \ #\ happens\ entirely\ in\ screen-space,\ because\ we\ need\ to\ draw\ right\n\ \ \ \ #\ to\ the\ screen\ right\ now,\ and\ we\ don't\ have\ a\ surface-to-clip\ for\n\ \ \ \ #\ that.\n\n\ \ \ \ #\ Downproject\ the\ whisker\ to\ screen-space.\n\ \ \ \ set\ from\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\]\n\ \ \ \ set\ to\ \[\$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$to\]\n\n\ \ \ \ When\ /target/\ has\ quad\ /q2/\ \{\n\ \ \ \ \ \ \ \ if\ \{\$target\ eq\ \$rect\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ displayVertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$q2\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ if\ \{\[::math::geometry::pointInsidePolygon\ \$to\ \$displayVertices\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ at\ \$target\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ -keep\ 50ms\ \$rect\ points\ \$direction\ with\ length\ \$l\ at\ \$target\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ green\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ When\ /nobody/\ claims\ \$rect\ points\ /anything/\ at\ /anything/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 16ms\ -key\ \[list\ \$rect\ pointer\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \[list\ \$from\ \$to\]\ width\ 4\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ center\ \$to\ radius\ 10\ thickness\ 5\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ filled\ false\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nOn\ unmatch\ \{\n\ \ \ \ Hold!\ -key\ \[list\ \$rect\ pointer\]\ \{\}\n\}\n\n\}\n
<unknown> claims builtin-programs/group.folk has program code return\n#\ FIXME:\ re-enable\ group.fol (
[ m2:0 (s5:0) ]
)<unknown> claims builtin-programs/group.folk has program code return\n#\ FIXME:\ re-enable\ group.folk\n\n#\ load\ all\ programs\nWhen\ group\ /group/\ contains\ /...programs/\ \{\n\ \ \ \ Wish\ tag\ \$group\ is\ stabilized\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ claim\ 'tag'\ specifically\ so\ it\ doesn't\ run\ twice\n\ \ \ \ \ \ \ \ Claim\ tag\ \$program\ has\ a\ program\n\ \ \ \ \}\n\}\n\n#\ figure\ out\ the\ text\ to\ display\ below\nWhen\ group\ /group/\ contains\ /...programs/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ /program/\ is\ titled\ /title/\]\ are\ /results/\ \{\n\ \ \ \ set\ programTitles\ \[dict\ create\]\n\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ programId\ \[dict\ get\ \$result\ program\]\n\n\ \ \ \ \ \ \ \ if\ \{\[lsearch\ \$programs\ \$programId\]\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ programTitles\ \$programId\ \[dict\ get\ \$result\ title\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ programTitleText\ \"\"\n\n\ \ \ \ foreach\ program\ \$programs\ \{\n\ \ \ \ \ \ \ \ set\ title\ \[dict_getdef\ \$programTitles\ \$program\ \"(no\ title)\"\]\n\ \ \ \ \ \ \ \ append\ programTitleText\ \\n\ \$program\ \":\ \"\ \$title\n\ \ \ \ \}\n\n\ \ \ \ Claim\ group\ \$group\ has\ program\ titles\ \$programTitleText\n\}\n\n#\ display\ said\ text\nWhen\ group\ /group/\ has\ program\ titles\ /programTitles/\ &\\\n\ \ \ \ \ /group/\ has\ region\ /r/\ \{\n\ \ \ \ set\ radians\ \[region\ angle\ \$r\]\n\ \ \ \ set\ pos\ \[region\ topleft\ \[region\ move\ \$r\ down\ 40px\ right\ 15px\]\]\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ text\ \$programTitles\ scale\ 0.7\ radians\ \$radians\ anchor\ topleft\n\}\n
<unknown> claims builtin-programs/music.folk has program code {if {[catch {exec which sclang}]} {
(
[ m3:0 (s7:0) ]
)<unknown> claims builtin-programs/music.folk has program code {if {[catch {exec which sclang}]} {
error "music: sclang doesn't exist; not running."
}
set musicDir $::env(HOME)/music
exec mkdir -p $musicDir
# https://raw.githubusercontent.com/tidalcycles/Tidal/main/BootTidal.hs
set bootTidal {
:set -XOverloadedStrings
:set prompt ""
import Sound.Tidal.Context
import System.IO (hSetEncoding, stdout, utf8)
hSetEncoding stdout utf8
tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})
:{
let only = (hush >>)
p = streamReplace tidal
hush = streamHush tidal
panic = do hush
once $ sound "superpanic"
list = streamList tidal
mute = streamMute tidal
unmute = streamUnmute tidal
unmuteAll = streamUnmuteAll tidal
unsoloAll = streamUnsoloAll tidal
solo = streamSolo tidal
unsolo = streamUnsolo tidal
once = streamOnce tidal
first = streamFirst tidal
asap = once
nudgeAll = streamNudgeAll tidal
all = streamAll tidal
resetCycles = streamResetCycles tidal
setCycle = streamSetCycle tidal
setcps = asap . cps
getcps = streamGetcps tidal
getnow = streamGetnow tidal
xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
jump i = transition tidal True (Sound.Tidal.Transition.jump) i
jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
d1 = p 1 . (|< orbit 0)
d2 = p 2 . (|< orbit 1)
d3 = p 3 . (|< orbit 2)
d4 = p 4 . (|< orbit 3)
d5 = p 5 . (|< orbit 4)
d6 = p 6 . (|< orbit 5)
d7 = p 7 . (|< orbit 6)
d8 = p 8 . (|< orbit 7)
d9 = p 9 . (|< orbit 8)
d10 = p 10 . (|< orbit 9)
d11 = p 11 . (|< orbit 10)
d12 = p 12 . (|< orbit 11)
d13 = p 13
d14 = p 14
d15 = p 15
d16 = p 16
:}
:{
let getState = streamGet tidal
setI = streamSetI tidal
setF = streamSetF tidal
setS = streamSetS tidal
setR = streamSetR tidal
setB = streamSetB tidal
:}
:set prompt "tidal> "
:set prompt-cont ""
default (Pattern String, Integer, Double)
}
set scStartup [open $musicDir/startup.sc w]
# via https://club.tidalcycles.org/t/tidal-synth-doesnt-work/800 -- it
# doesn't work if you just do SuperDirt.start; for some reason
puts $scStartup {(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 2048; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt.stop; // stop any old ones, avoid duplicate dirt (if it is nil, this won't do anything)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
SuperDirt.default = ~dirt; // make this instance available in sclang (optional)
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
// directly below here, in your own copy of this file, you could add further code that you want to call on startup
// this makes sure the server and ~dirt are running
// you can keep this separate and make it easier to switch between setups
// by using "path/to/my/file.scd".load and if necessary commenting out different load statements
// ...
};
s.latency = 0.3; // increase this if you get "late" messages
};
);}
close $scStartup
set uid [exec id -u $::env(USER)]
set ::env(DBUS_SESSION_BUS_ADDRESS) "unix:path=/run/user/$uid/bus"
exec rm -f $musicDir/music.log
fn musicExec {args} {
if {[lindex $args end] eq "&"} {
exec {*}[lreplace $args end end] >>$musicDir/music.log 2>>$musicDir/music.log &
} else {
exec {*}$args >>$musicDir/music.log 2>>$musicDir/music.log
}
}
fn musicFinishSetup {} {
if {$::thisNode eq "folk-hex"} {
exec jackd -d alsa -d hdmi:CARD=NVidia -r 48000 -p 1024 -n 2 &
} elseif {$::thisNode eq "folk-sva"} {
exec jackd -d alsa -d hdmi:CARD=Generic,DEV=1 -r 48000 -p 1024 -n 2 &
}
catch {exec pkill ghci}
catch {exec pkill ghc}
catch {exec pkill sclang}
catch {exec pkill scsynth}
sleep 0.4
set ::env(QT_QPA_PLATFORM) offscreen
musicExec sclang $musicDir/startup.sc &
set fifo $musicDir/tidal-input
exec rm -f $fifo
exec mkfifo $fifo
sleep 0.2
musicExec sh -c "ghci < $fifo" &
set fifoId [open $fifo w]
puts $fifoId $bootTidal; flush $fifoId
# We keep $fifoId open so that ghci doesn't get an EOF.
}
while true {
puts "music: Waiting for D-Bus."
sleep 0.2
if {[file exists /run/user/$uid/bus]} {
puts "music: Found D-Bus."
musicFinishSetup
break
}
}
}
<unknown> claims builtin-programs/tags-to-quads.folk has program code When\ libapriltag\ has\ been\ b (
[ m4:0 (s20:0) ]
)<unknown> claims builtin-programs/tags-to-quads.folk has program code When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\n#\ Represents\ camera\ or\ projector\ intrinsics,\ including\ the\ classic\n#\ intrinsic\ matrix\ but\ also\ dimensions\ at\ which\ the\ matrix\ was\ created\n#\ +\ distortion\ coefficients.\n#\n#\ Intrinsic\ matrix:\n#\ \ \ fx\ \ s\ \ \ cx\n#\ \ \ 0\ \ \ fy\ \ cy\n#\ \ \ 0\ \ \ 0\ \ \ \ 1\n\$cc\ struct\ Intrinsics\ \{\n\ \ \ \ double\ width\;\n\ \ \ \ double\ height\;\n\n\ \ \ \ double\ fx\;\n\ \ \ \ double\ fy\;\n\ \ \ \ double\ cx\;\n\ \ \ \ double\ cy\;\n\ \ \ \ double\ s\;\n\n\ \ \ \ double\ k1\;\n\ \ \ \ double\ k2\;\n\n\ \ \ \ double\ p1\;\n\ \ \ \ double\ p2\;\n\}\n\n#\ Intrinsics\ helpers:\n\$cc\ proc\ distort\ \{double\ fx\ double\ fy\ double\ cx\ double\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ k1\ double\ k2\ double\ p1\ double\ p2\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\]\ double\ out\[2\]\}\ void\ \{\n\ \ \ \ double\ x\ =\ (xy\[0\]\ -\ cx)/fx\;\n\ \ \ \ double\ y\ =\ (xy\[1\]\ -\ cy)/fy\;\n\ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ double\ radial\ =\ k1\ *\ r2\ +\ k2\ *\ r2*r2\;\n\ \ \ \ double\ dx\ =\ 2*p1*x*y\ +\ p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ double\ dy\ =\ p1*(r2\ +\ 2*y*y)\ +\ 2*p2*x*y\;\n\ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*fx\ +\ cx\;\n\ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*fy\ +\ cy\;\n\}\n\$cc\ proc\ project\ \{Intrinsics\ intr\ double\ width\ double\ height\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[3\]\ v\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ v\[0\]*intr.fx\ +\ \ v\[1\]*intr.s\ +\ v\[2\]*intr.cx,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[1\]*intr.fy\ +\ v\[2\]*intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ \ \ \ \ \ \ \ \ \ \ \ 0\ +\ v\[2\]\n\ \ \ \ \}\;\n\ \ \ \ out\[0\]\ /=\ out\[2\]\;\ out\[1\]\ /=\ out\[2\]\;\n\ \ \ \ distort(intr.fx,\ intr.fy,\ intr.cx,\ intr.cy,\n\ \ \ \ \ \ \ \ \ \ \ \ intr.k1,\ intr.k2,\ intr.p1,\ intr.p2,\n\ \ \ \ \ \ \ \ \ \ \ \ out,\ out)\;\n\ \ \ \ out\[0\]\ *=\ width\ /\ intr.width\;\n\ \ \ \ out\[1\]\ *=\ height\ /\ intr.height\;\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[0\]),\n\ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ out\[1\])\n\ \ \ \ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ rescaleAndUndistort\ \{Intrinsics\ intr\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ in\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ out\}\ void\ \{\n\ \ \ \ double\ x\ =\ in\[0\]\ *\ intr.width\ /\ cameraWidth\;\n\ \ \ \ double\ y\ =\ in\[1\]\ *\ intr.height\ /\ cameraHeight\;\n\n\ \ \ \ double\ x0\ =\ (x\ -\ intr.cx)\ /\ intr.fx\;\n\ \ \ \ double\ y0\ =\ (y\ -\ intr.cy)\ /\ intr.fy\;\n\ \ \ \ x\ =\ x0\;\ y\ =\ y0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \}\n\ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\n\ \ \ \ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\}\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ #define\ MATD_VAR(name,\ nr,\ nc)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ name\ =\ alloca(sizeof(matd_t))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->data\ =\ alloca((nr)*(nc)*sizeof(double))\;\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ name->nrows\ =\ nr\;\ name->ncols\ =\ nc\;\n\}\n\$cc\ proc\ pseudoInverse\ \{matd_t*\ a\}\ matd_t*\ \{\n\ \ \ \ matd_svd_t\ usv\ =\ matd_svd(a)\;\n\n\ \ \ \ MATD_VAR(Sinv,\ usv.S->ncols,\ usv.S->nrows)\;\n\ \ \ \ memset(Sinv->data,\ 0,\ sizeof(double)*Sinv->nrows*Sinv->ncols)\;\n\ \ \ \ for\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ usv.S->nrows\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (i\ >=\ usv.S->ncols)\ \{\ break\;\ \}\n\ \ \ \ \ \ \ \ double\ el\ =\ MATD_EL(usv.S,\ i,\ i)\;\n\ \ \ \ \ \ \ \ if\ (el\ >\ MATD_EPS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(Sinv,\ i,\ i)\ =\ 1.0\ /\ el\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ pinv\ =\ matd_op(\"M*M*(M')\",\ usv.V,\ Sinv,\ usv.U)\;\n\ \ \ \ matd_destroy(usv.V)\;\ matd_destroy(usv.S)\;\ matd_destroy(usv.U)\;\n\ \ \ \ return\ pinv\;\n\}\n\n\$cc\ code\ \{\ \nvoid\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \}\;\n\ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\}\ \}\n\n#\ Based\ on:\ https://visp-doc.inria.fr/doxygen/camera_localization/tutorial-pose-gauss-newton-opencv.html\n\n#\ Outputs\ to\ dt\ and\ dR\ (which\ should\ have\ been\ allocated\ by\ the\ caller).\n\$cc\ proc\ exponentialMap\ \{matd_t*\ v\ matd_t*\ dt\ matd_t*\ dR\}\ void\ \{\n\ \ \ \ double\ vx\ =\ MATD_EL(v,\ 0,\ 0)\;\n\ \ \ \ double\ vy\ =\ MATD_EL(v,\ 1,\ 0)\;\n\ \ \ \ double\ vz\ =\ MATD_EL(v,\ 2,\ 0)\;\n\ \ \ \ double\ vtux\ =\ MATD_EL(v,\ 3,\ 0)\;\n\ \ \ \ double\ vtuy\ =\ MATD_EL(v,\ 4,\ 0)\;\n\ \ \ \ double\ vtuz\ =\ MATD_EL(v,\ 5,\ 0)\;\n\ \ \ \ MATD_VAR(tu,\ 3,\ 1)\;\ //\ theta\ u\n\ \ \ \ MATD_EL(tu,\ 0,\ 0)\ =\ vtux\;\n\ \ \ \ MATD_EL(tu,\ 1,\ 0)\ =\ vtuy\;\n\ \ \ \ MATD_EL(tu,\ 2,\ 0)\ =\ vtuz\;\n\ \ \ \ //\ Rodrigues\ from\ tu\ to\ dR\n\ \ \ \ rotationVectorToRotationMatrix(tu->data,\ (double\ (*)\[3\])\ dR->data)\;\n\n\ \ \ \ double\ theta\ =\ sqrt(matd_vec_dot_product(tu,\ tu))\;\n\ \ \ \ double\ sinc\ =\ (fabs(theta)\ <\ 1.0e-8)\ ?\ 1.0\ :\ sin(theta)\ /\ theta\;\n\ \ \ \ double\ mcosc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ 0.5\ :\ (1.-cos(theta))\ /\ theta\ /\ theta\;\n\ \ \ \ double\ msinc\ =\ (fabs(theta)\ <\ 2.5e-4)\ ?\ (1./6.)\ :\ (1.-sin(theta)/theta)\ /\ theta\ /\ theta\;\n\n\ \ \ \ MATD_EL(dt,\ 0,\ 0)\ =\ vx*(sinc\ +\ vtux*vtux*msinc)\n\ \ \ \ \ \ \ \ +\ vy*(vtux*vtuy*msinc\ -\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(vtux*vtuz*msinc\ +\ vtuy*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 1,\ 0)\ =\ vx*(vtux*vtuy*msinc\ +\ vtuz*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(sinc\ +\ vtuy*vtuy*msinc)\n\ \ \ \ \ \ \ \ +\ vz*(vtuy*vtuz*msinc\ -\ vtux*mcosc)\;\n\ \ \ \ MATD_EL(dt,\ 2,\ 0)\ =\ vx*(vtux*vtuz*msinc\ -\ vtuy*mcosc)\n\ \ \ \ \ \ \ \ +\ vy*(vtuy*vtuz*msinc\ +\ vtux*mcosc)\n\ \ \ \ \ \ \ \ +\ vz*(sinc\ +\ vtuz*vtuz*msinc)\;\n\}\n\n#\ wX\ is\ the\ model\ 3D\ coordinates\ (for\ all\ 4\ tag\ corners).\ x\ is\ the\ 4\n#\ current\ detected\ tag\ corners\ in\ the\ image,\ in\ normalized\n#\ coordinates.\ cRw\ and\ ctw\ are\ pose\ estimates\ that\ get\ refined\ (and\n#\ replaced\;\ they\ may\ be\ destroyed\ by\ us).\ The\ caller\ has\ the\n#\ responsibility\ to\ free\ the\ returned\ cRw\ and\ ctw.\n\$cc\ proc\ poseGaussNewton\ \{double\[\]\[3\]\ wX\ double\[\]\[2\]\ x\ int\ npoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t**\ cRw\ matd_t**\ ctw\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ maxIters\}\ void\ \{\n\ \ \ \ MATD_VAR(J,\ npoints*2,\ 6)\;\n\ \ \ \ double\ lambda\ =\ 0.25\;\n\ \ \ \ MATD_VAR(xq,\ npoints*2,\ 1)\;\n\ \ \ \ MATD_VAR(xn,\ npoints*2,\ 1)\;\n\n\ \ \ \ double\ residual\ =\ 0\;\ double\ residual_prev\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2,\ 0)\ =\ x\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ MATD_EL(xn,\ i*2+1,\ 0)\ =\ x\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ MATD_VAR(wXi,\ 3,\ 1)\;\n\ \ \ \ int\ iters\ =\ 0\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ npoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ matd_set_data(wXi,\ wX\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ cX\ =\ matd_op(\"(M*M)+M\",\ *cRw,\ wXi,\ *ctw)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Xi\ =\ MATD_EL(cX,\ 0,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Yi\ =\ MATD_EL(cX,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Zi\ =\ MATD_EL(cX,\ 2,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ matd_destroy(cX)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ Xi/Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ Yi/Zi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ x(q)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2,\ 0)\ =\ xi\;\ \ \ //\ x(q)\ =\ cX/cZ\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(xq,\ i*2+1,\ 0)\ =\ yi\;\ //\ y(q)\ =\ cY/cZ\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Update\ J\ using\ equation\ (11)\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 0)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 1)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 2)\ =\ xi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 3)\ =\ xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 4)\ =\ -(1\ +\ xi\ *\ xi)\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2,\ 5)\ =\ yi\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 0)\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 1)\ =\ -1\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 2)\ =\ yi\ /\ Zi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 3)\ =\ 1\ +\ yi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 4)\ =\ -xi\ *\ yi\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(J,\ i*2+1,\ 5)\ =\ -xi\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ matd_t*\ e_q\ =\ matd_op(\"M-M\",\ xq,\ xn)\;\ //\ Equation\ (7)\n\n\ \ \ \ \ \ \ \ matd_t*\ Jp\ =\ pseudoInverse(J)\;\n\ \ \ \ \ \ \ \ matd_scale_inplace(Jp,\ -lambda)\;\n\ \ \ \ \ \ \ \ matd_t*\ dq\ =\ matd_multiply(Jp,\ e_q)\;\n\ \ \ \ \ \ \ \ MATD_VAR(dctw,\ 3,\ 1)\;\ MATD_VAR(dcRw,\ 3,\ 3)\;\n\ \ \ \ \ \ \ \ exponentialMap(dq,\ dctw,\ dcRw)\;\n\n\ \ \ \ \ \ \ \ matd_t*\ old_cRw\ =\ *cRw\;\ matd_t*\ old_ctw\ =\ *ctw\;\n\ \ \ \ \ \ \ \ *cRw\ =\ matd_op(\"(M')*M\",\ dcRw,\ *cRw)\;\n\ \ \ \ \ \ \ \ *ctw\ =\ matd_op(\"(M')*(M-M)\",\ dcRw,\ *ctw,\ dctw)\;\n\ \ \ \ \ \ \ \ matd_destroy(old_cRw)\;\ matd_destroy(old_ctw)\;\n\n\ \ \ \ \ \ \ \ residual_prev\ =\ residual\;\n\ \ \ \ \ \ \ \ residual\ =\ matd_vec_dot_product(e_q,\ e_q)\;\n\n\ \ \ \ \ \ \ \ matd_destroy(e_q)\;\n\ \ \ \ \ \ \ \ matd_destroy(Jp)\;\n\ \ \ \ \ \ \ \ matd_destroy(dq)\;\n\n\ \ \ \ \ \ \ \ if\ (iters++\ >\ maxIters)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"tags-to-quads:\ TOO\ MANY\ ITERS\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ while\ (fabs(residual\ -\ residual_prev)\ >\ MATD_EPS)\;\n\n\ \ \ \ /*\ exit(1)\;\ */\n\}\n\n#\ TagPose\ represents\ a\ rotation\ and\ translation\ from\ tag-space\ (where\n#\ (0,\ 0,\ 0)\ is\ the\ center\ of\ the\ tag)\ to\ camera-space\ (where\ (0,\ 0,\ 0)\n#\ is\ the\ center\ of\ the\ camera\ lens).\n\$cc\ struct\ TagPose\ \{\n\ \ \ \ double\ R\[3\]\[3\]\;\n\ \ \ \ double\ t\[3\]\[1\]\;\n\}\n\n\$cc\ proc\ servoingEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\ TagPose\ prevTagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ double\ r\ =\ tagSize\ /\ 2.0\;\n\ \ \ \ double\ wX\[\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-r,\ \ r,\ 0\},\ \{\ r,\ \ r,\ 0\},\n\ \ \ \ \ \ \ \ \{\ r,\ -r,\ 0\},\ \{-r,\ -r,\ 0\}\n\ \ \ \ \}\;\n\n\ \ \ \ double\ x\[4\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ //\ Change\ p0\ so\ we\ can\ apply\ intrinsics:\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ x\[i\])\;\n\ \ \ \ \ \ \ \ //\ Apply\ intrinsics\ to\ go\ from\ pixel\ coordinates\ to\ normalized\n\ \ \ \ \ \ \ \ //\ image-plane\ coordinates:\n\ \ \ \ \ \ \ \ x\[i\]\[0\]\ =\ (x\[i\]\[0\]\ -\ cameraIntrinsics.cx)\ /\ cameraIntrinsics.fx\;\n\ \ \ \ \ \ \ \ x\[i\]\[1\]\ =\ (x\[i\]\[1\]\ -\ cameraIntrinsics.cy)\ /\ cameraIntrinsics.fy\;\n\ \ \ \ \}\n\n\ \ \ \ matd_t*\ cRw\ =\ matd_create_data(3,\ 3,\ (double*)\ prevTagPose.R)\;\n\ \ \ \ matd_t*\ ctw\ =\ matd_create_data(3,\ 1,\ (double*)\ prevTagPose.t)\;\n\n\ \ \ \ poseGaussNewton(wX,\ x,\ 4,\ &cRw,\ &ctw,\ 50)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ cRw->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ ctw->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(cRw)\;\n\ \ \ \ matd_destroy(ctw)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ baseEstimateTagPose\ \{Intrinsics\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ cameraWidth\ double\ cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ tagSize\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[4\]\[2\]\ p0\}\ TagPose\ \{\n\ \ \ \ //\ We'll\ fill\ this\ in\ with\ a\ new\ .p\ and\ .H\ with\n\ \ \ \ //\ undistorted/rescaled\ coordinates.\n\ \ \ \ apriltag_detection_t\ det\;\n\n\ \ \ \ //\ We'll\ fill\ in\ the\ right\ side\ of\ each\ correspondence\ in\ the\n\ \ \ \ //\ loop.\n\ \ \ \ float\ correspondences\[4\]\[4\]\ =\ \{\n\ \ \ \ \ \ \ \ \{-1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ 1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{1.0f,\ -1.0f,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \{-1.0f,\ -1.0f,\ 0,\ 0\}\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 4\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rescaleAndUndistort(cameraIntrinsics,\ cameraWidth,\ cameraHeight,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\[i\],\ det.p\[i\])\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[2\]\ =\ det.p\[i\]\[0\]\;\n\ \ \ \ \ \ \ \ correspondences\[i\]\[3\]\ =\ det.p\[i\]\[1\]\;\n\ \ \ \ \}\n\n\ \ \ \ zarray_t\ correspondencesArr\ =\ \{\n\ \ \ \ \ \ \ \ .el_sz\ =\ sizeof(float\[4\]),\ .size\ =\ 4,\ .alloc\ =\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ (char*)\ correspondences\n\ \ \ \ \}\;\n\ \ \ \ det.H\ =\ homography_compute(&correspondencesArr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ HOMOGRAPHY_COMPUTE_FLAG_SVD)\;\n\ \ \ \ apriltag_detection_info_t\ info\ =\ \{\n\ \ \ \ \ \ \ \ .det\ =\ &det,\n\ \ \ \ \ \ \ \ .tagsize\ =\ tagSize,\n\ \ \ \ \ \ \ \ .fx\ =\ cameraIntrinsics.fx,\ .fy\ =\ cameraIntrinsics.fy,\n\ \ \ \ \ \ \ \ .cx\ =\ cameraIntrinsics.cx,\ .cy\ =\ cameraIntrinsics.cy\n\ \ \ \ \}\;\n\ \ \ \ apriltag_pose_t\ pose\;\n\ \ \ \ estimate_pose_for_tag_homography(&info,\ &pose)\;\n\n\ \ \ \ matd_destroy(det.H)\;\n\n\ \ \ \ TagPose\ ret\;\n\ \ \ \ memcpy(ret.R,\ pose.R->data,\ sizeof(ret.R))\;\n\ \ \ \ memcpy(ret.t,\ pose.t->data,\ sizeof(ret.t))\;\n\n\ \ \ \ matd_destroy(pose.R)\;\n\ \ \ \ matd_destroy(pose.t)\;\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ poseDistSq\ \{\ TagPose\ p1\ TagPose\ p2\ \}\ double\ \{\n\ \ \ \ double\ delta_x\ =\ p2.t\[0\]\[0\]\ -\ p1.t\[0\]\[0\]\;\n\ \ \ \ double\ delta_y\ =\ p2.t\[1\]\[0\]\ -\ p1.t\[1\]\[0\]\;\n\ \ \ \ double\ delta_z\ =\ p2.t\[2\]\[0\]\ -\ p1.t\[2\]\[0\]\;\n\n\ \ \ \ return\ delta_x\ *\ delta_x\ +\ delta_y\ *\ delta_y\ +\ delta_z\ *\ delta_z\;\n\}\n\nset\ poseLib\ \[\$cc\ compile\]\nClaim\ the\ pose\ library\ is\ \$poseLib\n\n#\ All\ spaces\ are\ in\ meters.\ To\ transform\ a\ point\ from\ one\ space\ to\ another,\ it\ will\ execute\n#\ a\ partially\ evaluated\ function\ located\ in\ `changers`\ (all\ implementations\ currently\ just\n#\ translate\ and\ rotate)\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ collected\ results\ for\ \[list\ the\ changer\ from\ space\ /sourceSpace/\ to\ space\ /targetSpace/\ is\ /changer/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ changers\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ dict\ set\ changers\ \$sourceSpace\ \$targetSpace\ \$changer\n\ \ \ \ \}\ \}\n\n\ \ \ \ fn\ quadChange\ \{q\ targetSpace\}\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ quad\ changer\ is\ \[fn\ quadChange\]\n\}\n\nWhen\ camera\ /camera/\ to\ display\ /display/\ has\ extrinsics\ /extrinsics/\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ set\ R\ \[dict\ get\ \$extrinsics\ R\]\n\ \ \ \ set\ t\ \[dict\ get\ \$extrinsics\ t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \$camera\ to\ space\ \"display\ \$display\"\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{R\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\ \$R\ \$t\]\n\n\ \ \ \ Claim\ the\ changer\ from\ space\ \"display\ \$display\"\ to\ space\ \$camera\ is\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \[list\ \{Rt\ t\ v\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$Rt\ \[sub\ \$v\ \$t\]\]\ \$v\n\ \ \ \ \ \ \ \ \}\]\ \[math::linearalgebra::transpose\ \$R\]\ \$t\]\n\}\n\nset\ quadLib\ \[library\ create\ quadLib\ \{\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\n\ \ \ \ rename\ scale\ scaleVector\n\n\ \ \ \ proc\ create\ \{space\ vertices\}\ \{\ list\ \$space\ \$vertices\ \}\n\ \ \ \ proc\ space\ \{q\}\ \{\ lindex\ \$q\ 0\ \}\n\ \ \ \ proc\ vertices\ \{q\}\ \{\ lindex\ \$q\ 1\ \}\n\n\ \ \ \ #\ Scales\ about\ the\ centroid\ of\ the\ quad,\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad.\ You\ can\ scale\ by\ a\ percentage\ or\ set\ a\ specific\ length\n\ \ \ \ #\ in\ meters/centimeters/millimeters\ (which\ just\ sets\ the\ quad\ size\n\ \ \ \ #\ along\ that\ axis).\n\ \ \ \ proc\ scale\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[lindex\ \$args\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ args\ \[list\ width\ \$value\ height\ \$value\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ \ \ \ \ set\ sxp\ 1\;\ set\ syp\ 1\n\ \ \ \ \ \ \ \ foreach\ \{dim\ value\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\0-9\\.\]+)(cm|mm|m|%)?\}\ \$value\ ->\ value\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ scale\ value\ \$value\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$dim\ eq\ \"width\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \[/\ \$value\ \$width\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ sxp\ \[*\ \$sxp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$dim\ eq\ \"height\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"px\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[/\ \$value\ \$height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \[*\ \$value\ 0.01\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$unit\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ syp\ \[*\ \$syp\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ scale:\ Invalid\ dimension\ \$dim\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Calculate\ the\ centroid\n\ \ \ \ \ \ \ \ set\ c\ \[::math::linearalgebra::scale\ 0.25\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[add\ \$topLeft\ \$bottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \$topRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Calculate\ width\ and\ height\ vectors\ from\ the\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ #\ Width\ goes\ from\ left\ to\ right\ (topLeft\ ->\ topRight,\ bottomLeft\ ->\ bottomRight)\ \ \n\ \ \ \ \ \ \ \ #\ Height\ goes\ from\ top\ to\ bottom\ (topLeft\ ->\ bottomLeft,\ topRight\ ->\ bottomRight)\n\ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\ \n\ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Scale\ each\ vertex\ by\ moving\ from\ centroid\ along\ scaled\ width/height\ vectors\n\ \ \ \ \ \ \ \ #\ Each\ vertex\ =\ centroid\ +\ (width_factor\ *\ width_vector)\ +\ (height_factor\ *\ height_vector)\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopLeft\ \[add\ \$newTopLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorLeft\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorTop\]\]\n\ \ \ \ \ \ \ \ set\ newTopRight\ \[add\ \$newTopRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ -0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ 0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomRight\ \[add\ \$newBottomRight\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$c\ \[scaleVector\ \[expr\ \{\$sxp\ *\ -0.5\}\]\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ set\ newBottomLeft\ \[add\ \$newBottomLeft\ \[scaleVector\ \[expr\ \{\$syp\ *\ 0.5\}\]\ \$heightVectorLeft\]\]\n\n\ \ \ \ \ \ \ \ create\ \[space\ \$q\]\ \[list\ \$newTopLeft\ \$newTopRight\ \$newBottomRight\ \$newBottomLeft\]\n\ \ \ \ \}\n\ \ \ \ proc\ buffer\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{(\[\\-0-9\\.\]+)(cm|mm|m)?\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$topRight\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leftVector\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rightVector\ \[sub\ \$bottomRight\ \$topRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$leftVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$rightVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$topVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topVector\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomVector\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$bottomVector\]\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ buffer:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Moves\ the\ quad\ left/right/up/down\ along\ the\ width\ and\ height\n\ \ \ \ #\ directions\ of\ the\ quad\ (not\ the\ global\ x\ and\ y).\n\ \ \ \ proc\ move\ \{q\ args\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ width\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ height\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ foreach\ \{direction\ distance\}\ \$args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^(\[\\-0-9\\.\]+)(cm|mm|m|%)?\$\}\ \$distance\ ->\ distance\ unit\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ distance\ \$distance\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distance\ ==\ 0\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"%\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\ ||\ \$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$height\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$width\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"mm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.001\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ eq\ \"cm\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distance\ \[*\ \$distance\ 0.01\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unit\ \"m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$unit\ ne\ \"\"\ &&\ \$unit\ ne\ \"m\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ unit\ \$unit\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Calculate\ displacement\ based\ on\ quad's\ actual\ orientation\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$direction\ eq\ \"up\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ height\ (from\ bottom\ to\ top)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$topRight\ \$bottomRight\]\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"down\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ height\ direction\ (from\ top\ to\ bottom)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorLeft\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ heightVectorRight\ \[sub\ \$bottomRight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgHeightVector\ \[scaleVector\ 0.5\ \[add\ \$heightVectorLeft\ \$heightVectorRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgHeightVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ direction\ opposite\ to\ width\ (from\ right\ to\ left)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomLeft\ \$bottomRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$direction\ eq\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Move\ in\ the\ width\ direction\ (from\ left\ to\ right)\ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorTop\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ widthVectorBottom\ \[sub\ \$bottomRight\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ avgWidthVector\ \[scaleVector\ 0.5\ \[add\ \$widthVectorTop\ \$widthVectorBottom\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ disp\ \[scaleVector\ \$distance\ \[unitLengthVector\ \$avgWidthVector\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"quad\ move:\ Invalid\ direction\ \$direction\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topLeft\ \[add\ \$topLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$bottomRight\ \$disp\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$bottomLeft\ \$disp\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Move\ an\ existing\ geometry\ geom\ (object\ with\ width\ and\ height\n\ \ \ \ #\ keys)\ to\ align\ onto\ the\ plane\ &\ the\ top\ edge\ &\ left\ edge\ of\ the\n\ \ \ \ #\ existing\ quad\ q.\n\ \ \ \ proc\ alignGeometry\ \{q\ geom\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ \ \ \ \ set\ topDisp\ \[scaleVector\ \$geom(width)\ \[unitLengthVector\ \[sub\ \$topRight\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ leftDisp\ \[scaleVector\ \$geom(height)\ \[unitLengthVector\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\ \ \ \ \ \ \ \ set\ topRight\ \[add\ \$topLeft\ \$topDisp\]\n\ \ \ \ \ \ \ \ set\ bottomRight\ \[add\ \$topRight\ \$leftDisp\]\n\ \ \ \ \ \ \ \ set\ bottomLeft\ \[add\ \$topLeft\ \$leftDisp\]\n\ \ \ \ \ \ \ \ return\ \[create\ \[space\ \$q\]\ \[list\ \$topLeft\ \$topRight\ \$bottomRight\ \$bottomLeft\]\]\n\ \ \ \ \}\n\}\]\nClaim\ the\ quad\ library\ is\ \$quadLib\n\nWhen\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ Wish\ -keep\ 100ms\ \$tag\ has\ resolved\ geometry\n\}\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ camera\ /camera/\ has\ intrinsics\ /cameraIntrinsics/\ \{\n\n\ \ \ \ #\ for\ position\ stabilization\n\ \ \ \ set\ unfreezeThreshold\ 0.01\n\ \ \ \ set\ unfreezeThresholdSq\ \[expr\ \{\$unfreezeThreshold\ *\ \$unfreezeThreshold\}\]\n\ \ \ \ set\ unfreezeLength\ 0.3\ \;#\ in\ seconds\n\n\ \ \ \ When\ tag\ /tag/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ \ \ \ \ /tag/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ tagSize\ \[dict\ get\ \$geom\ tagSize\]\n\n\ \ \ \ \ \ \ \ set\ prevResults\ \[Query!\ tag\ \$tag\ has\ pose\ /tagPose/\ at\ timestamp\ /timestamp/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$prevResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ latestResult\ \[lindex\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[dict\ get\ \$b\ timestamp\]\ <\ \[dict\ get\ \$a\ timestamp\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\}\}\ \$prevResults\]\ 0\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTimestamp\ \[dict\ get\ \$latestResult\ timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Consider\ previous\ tag\ pose\ if\ it's\ less\ than\ 200ms\ old:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$timestamp\ -\ \$prevTimestamp\ <\ 0.2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[dict\ get\ \$latestResult\ tagPose\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ prevTagPose\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevTagPose\ \[\$poseLib\ baseEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \[dict\ get\ \$det\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ tagPose\ \[\$poseLib\ servoingEstimateTagPose\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagSize\ \$prevTagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$det\ p\]\]\n\n\ \ \ \ \ \ \ \ ##\ tag\ stabilization\ ##\n\ \ \ \ \ \ \ \ #\ (can't\ use\ When\ here\ as\ it\ can't\ exfiltrate\ info).\ Is\ there\ a\ better\ way\ to\ do\ this?\n\ \ \ \ \ \ \ \ set\ stabilizedMatches\ \[Query!\ /someone/\ wishes\ tag\ \$tag\ is\ stabilized\]\n\ \ \ \ \ \ \ \ set\ isTagStabilized\ \[expr\ \{\[llength\ \$stabilizedMatches\]\ >\ 0\}\]\n\n\ \ \ \ \ \ \ \ if\ \{\$isTagStabilized\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ stateResults\ \[Query!\ tag\ \$tag\ is\ stabilized\ with\ state\ /state/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$stateResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ get\ \[lindex\ \$stateResults\ 0\]\ state\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ state\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ distSq\ \[\$poseLib\ poseDistSq\ \$frozenPose\ \$tagPose\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$distSq\ >\ \$unfreezeThresholdSq\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ reset\ timestamp\ even\ if\ it's\ already\ unfrozen\ to\ keep\ it\ unfrozen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ unfreezeTime\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$frozen\ &&\ \$timestamp\ -\ \$unfreezeTime\ >\ \$unfreezeLength\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozenPose\ \$tagPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ frozen\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$frozen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ tagPose\ \$frozenPose\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ first\ time,\ so\ we'll\ init\ some\ stuff\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ (starts\ unfrozen)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ state\ \[dict\ create\ frozen\ 0\ frozenPose\ \$tagPose\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unfreezeTime\ \$timestamp\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ \$tag\ stabilization\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ is\ stabilized\ with\ state\ \$state\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Note\ that\ (for\ now)\ this\ pose\ statement\ is\ only\ imperatively\n\ \ \ \ \ \ \ \ #\ queried\ (by\ future\ invocations\ of\ this\ same\ code),\ not\n\ \ \ \ \ \ \ \ #\ reacted\ to.\ No\ need\ to\ give\ it\ a\ keep\ time.\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ tag\ pose\ \$tag\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ pose\ \$tagPose\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ set\ r\ \[expr\ \{\$tagSize\ /\ 2\}\]\n\ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ set\ vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \[-\ \$r\]\ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \[-\ \$r\]\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \ \ \ \$r\ \ \ \ \ \$r\ \ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \ \[-\ \$r\]\ \ \ \ \$r\ \ 0\]\]\n\n\ \ \ \ \ \ \ \ set\ R\ \[dict\ get\ \$tagPose\ R\]\;\ set\ t\ \[dict\ get\ \$tagPose\ t\]\n\ \ \ \ \ \ \ \ set\ vertices\ \[lmap\ v\ \$vertices\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ add\ \[matmul\ \$R\ \$v\]\ \$t\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ set\ quad\ \[\$quadLib\ create\ \$camera\ \$vertices\]\n\ \ \ \ \ \ \ \ Claim\ tag\ \$tag\ has\ quad\ \$quad\n\ \ \ \ \}\n\}\n\n\nWhen\ /tag/\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ tag\ /tag/\ has\ quad\ /q/\ \{\n\n\ \ \ \ set\ pageQuad\ \[\$quadLib\ buffer\ \$q\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \[dict\ getdef\ \$geom\ top\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \[dict\ getdef\ \$geom\ right\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \[dict\ getdef\ \$geom\ left\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \[dict\ getdef\ \$geom\ bottom\ 0\]\]\n\ \ \ \ Claim\ \$tag\ has\ quad\ \$pageQuad\n\}\n\nWhen\ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /tag/\ has\ canvas\ /writableTextureId/\ with\ /...wiOptions/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ #\ Composite\ each\ quad's\ canvas\ onto\ the\ screen\ based\ on\n\ \ \ \ #\ its\ quad.\n\ \ \ \ set\ displayToClip\ \[list\ \\\n\ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0/\$displayWidth\}\]\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0/\$displayHeight\}\]\ -1\]\ \\\n\ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ When\ -atomically\ \$tag\ has\ quad\ /quad/\ \{\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$quad\ \"display\ \$disp\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ a\ b\ c\ d\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$wiOptions\ layer\ 0\]\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/laser.folk has program code When\ the\ image\ library\ is\ /imageLi (
[ m5:0 (s11:0) ]
)<unknown> claims builtin-programs/laser.folk has program code When\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ endcflags\ vendor/blobdetect/hk.c\n\$cc\ extend\ \$imageLib\n\n\$cc\ include\ <apriltag.h>\n\$cc\ include\ <math.h>\n\$cc\ code\ \{\n\ \ \ \ int\ hoshen_kopelman(int\ **matrix,\ int\ m,\ int\ n)\;\n\n\ \ \ \ typedef\ struct\ \{\n\ \ \ \ \ \ \ \ int\ id\;\n\n\ \ \ \ \ \ \ \ //\ The\ center\ of\ the\ detection\ in\ image\ pixel\ coordinates.\n\ \ \ \ \ \ \ \ double\ c\[2\]\;\n\n\ \ \ \ \ \ \ \ //\ The\ corners\ of\ the\ tag\ in\ image\ pixel\ coordinates.\ These\ always\n\ \ \ \ \ \ \ \ //\ wrap\ counter-clock\ wise\ around\ the\ tag.\n\ \ \ \ \ \ \ \ //\ TL\ BL\ BR\ TR\n\ \ \ \ \ \ \ \ double\ p\[4\]\[2\]\;\n\n\ \ \ \ \ \ \ \ int\ size\;\n\ \ \ \ \}\ detected_blob_t\;\n\n\ \ \ \ zarray_t\ *blob_detector_detect(image_u8_t\ *im_orig,\ int\ threshold)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ zarray_create(sizeof(detected_blob_t*))\;\n\n\ \ \ \ \ \ \ \ //\ m\ =\ rows,\ n\ =\ columns\n\ \ \ \ \ \ \ \ int\ m\ =\ im_orig->height\;\n\ \ \ \ \ \ \ \ int\ n\ =\ im_orig->width\;\n\ \ \ \ \ \ \ \ int\ **matrix\;\n\ \ \ \ \ \ \ \ matrix\ =\ (int\ **)malloc(m\ *\ sizeof(int\ *))\;\n\ \ \ \ \ \ \ \ for(int\ i\ =\ 0\;\ i\ <\ m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ matrix\[i\]\ =\ (int\ *)malloc(n\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ for(int\ i\ =\ 0\;\ i\ <\ rows\;\ i++)\n\ \ \ \ \ \ \ \ //\ \ \ \ \ memset(matrix\[i\],\ 0,\ cols\ *\ sizeof(int))\;\n\n\ \ \ \ \ \ \ \ //\ filter\ the\ raster\ into\ on\ or\ off\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im_orig->height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im_orig->width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ im_orig->stride\ +\ x\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ v\ =\ im_orig->buf\[i\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ threshold\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ ((threshold\ >=\ 0\ &&\ v\ >\ threshold)\ ||\ (threshold\ <\ 0\ &&\ v\ <\ -threshold))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ v\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matrix\[y\]\[x\]\ =\ v\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ clusters\ =\ hoshen_kopelman(matrix,m,n)\;\n\ \ \ \ \ \ \ \ //\ printf(\"clusters:\ %d\\n\",\ clusters)\;\n\n\ \ \ \ \ \ \ \ //\ initialize\ a\ structure\ \n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\ =\ calloc(1,\ sizeof(detected_blob_t))\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->size\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_add(detections,\ &det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j=0\;\ j<n\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"%d\ \",matrix\[i\]\[j\])\;\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (matrix\[i\]\[j\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ matrix\[i\]\[j\]-1,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ +=\ j\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ +=\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->size\ +=\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ printf(\"\\n\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<clusters\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->id\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\]\ =\ det->c\[0\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \ \ \ \ det->c\[1\]\ =\ det->c\[1\]\ /\ det->size\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ for\ (int\ i=0\;\ i<m\;\ i++)\n\ \ \ \ \ \ \ \ \ \ \ \ free(matrix\[i\])\;\n\ \ \ \ \ \ \ \ free(matrix)\;\n\n\ \ \ \ \ \ \ \ return\ detections\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detection_destroy(detected_blob_t\ *det)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ if\ (det\ ==\ NULL)\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\n\ \ \ \ \ \ \ \ free(det)\;\n\ \ \ \ \}\n\n\ \ \ \ void\ blob_detections_destroy(zarray_t\ *detections)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ zarray_size(detections)\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ blob_detection_destroy(det)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ detect\ \{Image\ gray\ int\ threshold\}\ Jim_Obj*\ \{\n\ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1)\;\n\ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.bytesPerRow,\ .buf\ =\ gray.data\ \}\;\n\n\ \ \ \ zarray_t\ *detections\ =\ blob_detector_detect(&im,\ threshold)\;\n\ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ detected_blob_t\ *det\;\n\ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ printf(\"detection\ %3d:\ id\ %-4d\\n\ cx\ %f\ cy\ %f\ size\ %d\\n\",\ i,\ det->id,\ det->c\[0\],\ det->c\[1\],\ det->size)\;\n\n\ \ \ \ \ \ \ \ //\ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ int\ size\ =\ det->size\;\n\ \ \ \ \ \ \ \ char\ buf\[512\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ sizeof(buf),\ \"id\ %d\ center\ \{%f\ %f\}\ corners\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size)\;\n\ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ blob_detections_destroy(detections)\;\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ return\ result\;\n\}\n\nset\ blobdetectLib\ \[\$cc\ compile\]\n\nWhen\ /someone/\ wishes\ to\ detect\ laser\ blobs\ &\\\n\ \ \ \ \ camera\ /any/\ has\ gray\ frame\ /grayFrame/\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ set\ blobTime\ \[time\ \{\n\ \ \ \ \ \ \ \ set\ threshold\ 250\n\ \ \ \ \ \ \ \ set\ blobs\ \[\$blobdetectLib\ detect\ \$grayFrame\ \$threshold\]\n\ \ \ \ \}\]\n\ \ \ \ Hold!\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ blob\ detection\ time\ is\ \$blobTime\n\ \ \ \ \ \ \ \ foreach\ blob\ \$blobs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ laser\ blob\ \[dict\ get\ \$blob\ id\]\ has\ center\ \[dict\ get\ \$blob\ center\]\ size\ \[dict\ get\ \$blob\ size\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/mask-tags.folk has program code When\ the\ quad\ library\ is\ /quad (
[ m6:0 (s13:0) ]
)<unknown> claims builtin-programs/mask-tags.folk has program code When\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ width\ /projWidth/\ height\ /projHeight/\ &\\\n\ \ \ \ \ display\ /proj/\ has\ intrinsics\ /projectorIntrinsics/\ \{\n\ \ \ \ \ \ \ \ \n\ \ \ \ fn\ quadChange\n\n\ \ \ \ When\ tag\ /id/\ has\ quad\ /q/\ \{\n\ \ \ \ When\ -atomicallyWithKey\ \[list\ \$id\ quad\]\ \{\n\ \ \ \ \ \ \ \ set\ scaledQuad\ \[\$quadLib\ scale\ \$q\ 2.1\]\n\n\ \ \ \ \ \ \ \ lassign\ \[lmap\ v\ \[\$quadLib\ vertices\ \[quadChange\ \$scaledQuad\ \"display\ \$proj\"\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$projectorIntrinsics\ \$projWidth\ \$projHeight\ \$v\n\ \ \ \ \ \ \ \ \}\]\ p0\ p1\ p2\ p3\n\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$proj\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \$p0\ p1\ \$p1\ p2\ \$p2\ p3\ \$p3\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ black\ layer\ 100\n\ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/programs.folk has program code When\ tag\ /tag/\ has\ detection\ /a (
[ m7:0 (s17:0) ]
)<unknown> claims builtin-programs/programs.folk has program code When\ tag\ /tag/\ has\ detection\ /any/\ on\ camera\ /any/\ at\ timestamp\ /any/\ \{\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{\$tag\ >=\ 48600\}\ \{\ return\ \}\n\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ has\ a\ program\n\ \ \ \ Claim\ -keep\ 100ms\ tag\ \$tag\ is\ a\ tag\n\}\n\nWhen\ -noncapturing\ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\ \ \ \ When\ /type/\ /obj/\ has\ a\ program\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Added\ \$type\ \$obj\"\n\ \ \ \ \ \ \ \ On\ unmatch\ \{\ puts\ \"Removed\ \$type\ \$obj\"\ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[catch\ \{QueryOne!\ \$obj\ has\ demo\ code\ /demoCode/\}\ res\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$res(demoCode)\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.temp\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.temp\"\ r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \"\$saveDir/\$obj.folk\"\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\ ||\ \$::thisNode\ eq\ \"gadget-platinum\"\ ||\ \$::thisNode\ eq\ \"gadget-pink\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ 'Page\ fault'\ to\ folk-hex,\ try\ getting\ page\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ Ideally\ we\ would\ have\ some\ general\ (Avahi?)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ way\ of\ finding\ the\ 'authoritative'\ node\ on\ the\ local\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ network,\ or\ broadcasting\ out,\ and\ getting\ pages\ from\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ there.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ --output\ \"\$saveDir/\$obj.meta.folk\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"http://folk-hex.local:4273/printed-programs/\$obj.meta.folk\"\ &\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ It\ won't\ be\ reloaded\ until\ you\ redetect\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ err\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"No\ code\ for\ \$type\ \$obj\ (\$err):\\n\ \ \[errorInfo\ \$err\ \[info\ stacktrace\]\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ code\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.folk.edited\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \"\$saveDir/\$obj.folk.edited\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedCode\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[file\ mtime\ \"\$saveDir/\$obj.folk.edited\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$obj\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$obj\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$editedCode\ editedTime\ \$editedTime\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Claim\ \$obj\ has\ program\ code\ \$code\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ program\ \$obj\ is\ replaced\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editedTime\ \[dict\ get\ \$opts\ editedTime\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$obj\ is\ titled\ \"(edited\ \[clock\ format\ \$editedTime\ -format\ \"%a,\ %d\ %b\ %Y,\ %I:%M\ %p\"\])\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$obj.meta.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ mfd\ \[open\ \"\$saveDir/\$obj.meta.folk\"\ r\]\n\ \ \ \ \ \ \ \ \ \ \ set\ metacode\ \[read\ \$mfd\]\;\ close\ \$mfd\n\ \ \ \ \ \ \ \ \ \ \ apply\ \[list\ \{this\}\ \$metacode\]\ \$obj\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n
<unknown> claims builtin-programs/apriltags.folk has program code When\ the\ image\ library\ is\ /ima (
[ m8:0 (s22:0) ]
)<unknown> claims builtin-programs/apriltags.folk has program code When\ the\ image\ library\ is\ /imageLib/\ \{\n\n#\ To\ force\ a\ rebuild:\ rm\ -rf\ vendor/apriltag/build\n\n#\ Older\ versions\ of\ this\ file\ ran\ `patchelf\ --set-soname`\ (linux)\ or\n#\ `install_name_tool\ -id\ @executable_path/...`\ (darwin)\ on\ the\ built\n#\ library\ so\ it\ could\ be\ located\ at\ load\ time.\ We\ now\ embed\ an\ rpath\ on\n#\ the\ wrapper\ instead,\ but\ if\ a\ previously-mutated\ library\ is\ sitting\n#\ on\ disk,\ force\ a\ clean\ rebuild\ so\ its\ identity\ goes\ back\ to\ the\n#\ default\ and\ the\ wrapper's\ rpath\ can\ resolve\ it.\ Heuristic:\ if\ the\n#\ build\ is\ older\ than\ this\ file,\ assume\ it\ predates\ the\ new\ scheme.\nif\ \{\[file\ exists\ vendor/apriltag/build\]\ &&\n\ \ \ \ \[file\ exists\ vendor/apriltag/build/libapriltag.so\]\ &&\n\ \ \ \ \[file\ mtime\ vendor/apriltag/build/libapriltag.so\]\ <\ \\\n\ \ \ \ \ \ \ \ \[file\ mtime\ \$this\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ stale\ libapriltag\ build\ detected,\ rebuilding...\"\n\ \ \ \ file\ delete\ -force\ vendor/apriltag/build\n\}\n\nif\ \{!\[file\ exists\ vendor/apriltag/build/Makefile\]\}\ \{\n\ \ \ \ puts\ \"apriltags:\ Configuring\ libapriltag...\"\n\ \ \ \ exec\ cmake\ -B\ vendor/apriltag/build\ -S\ vendor/apriltag\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_BUILD_TYPE=Release\ -DBUILD_SHARED_LIBS=ON\ \\\n\ \ \ \ \ \ \ \ -DCMAKE_C_FLAGS=-march=native\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"apriltags:\ Building\ libapriltag...\"\nexec\ cmake\ --build\ vendor/apriltag/build\ --target\ apriltag\ \\\n\ \ \ \ >@stdout\ 2>@stderr\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ if\ \{!\[file\ exists\ vendor/apriltag/build/libapriltag.so\]\}\ \{\n\ \ \ \ \ \ \ \ exec\ ln\ -sf\ libapriltag.dylib\ vendor/apriltag/build/libapriltag.so\n\ \ \ \ \}\n\ \ \ \ set\ currentId\ \[string\ trim\ \[exec\ otool\ -D\ vendor/apriltag/build/libapriltag.dylib\ |\ tail\ -1\]\]\n\ \ \ \ if\ \{\$currentId\ ne\ \"@rpath/libapriltag.dylib\"\}\ \{\n\ \ \ \ \ \ \ \ exec\ install_name_tool\ -id\ @rpath/libapriltag.dylib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ vendor/apriltag/build/libapriltag.dylib\n\ \ \ \ \}\n\}\nputs\ \"apriltags:\ libapriltag\ built.\"\n\nfn\ configCcWithLibapriltag\ \{cc\}\ \{\n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n\}\nClaim\ libapriltag\ has\ been\ built\ with\ config\ \[fn\ configCcWithLibapriltag\]\n\nfn\ makeAprilTagDetector\ \{TAG_FAMILY\ QUAD_DECIMATE\ NTHREADS\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ configCcWithLibapriltag\ \$cc\n\ \ \ \ \$cc\ include\ <apriltag.h>\n\ \ \ \ \$cc\ include\ <\$TAG_FAMILY.h>\n\ \ \ \ \$cc\ include\ <math.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ static\ apriltag_detector_t\ *td\;\n\ \ \ \ \ \ \ \ static\ apriltag_family_t\ *tf\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ detectInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ td\ =\ apriltag_detector_create()\;\n\ \ \ \ \ \ \ \ tf\ =\ \$\{TAG_FAMILY\}_create()\;\n\ \ \ \ \ \ \ \ apriltag_detector_add_family_bits(td,\ tf,\ 3)\;\n\ \ \ \ \ \ \ \ td->quad_decimate\ =\ \$\{QUAD_DECIMATE\}\;\n\ \ \ \ \ \ \ \ td->nthreads\ =\ \$\{NTHREADS\}\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detect\ \{Image\ gray\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(gray.components\ ==\ 1\ ||\ gray.components\ ==\ 3)\;\n\ \ \ \ \ \ \ \ uint8_t*\ grayBuf\ =\ gray.data\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ grayBuf\ =\ malloc(gray.width\ *\ gray.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ gray.width\ *\ gray.height\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ r\ =\ gray.data\[i*3\],\ g\ =\ gray.data\[i*3+1\],\ b\ =\ gray.data\[i*3+2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grayBuf\[i\]\ =\ (uint8_t)(0.299f*r\ +\ 0.587f*g\ +\ 0.114f*b\ +\ 0.5f)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ image_u8_t\ im\ =\ (image_u8_t)\ \{\ .width\ =\ gray.width,\ .height\ =\ gray.height,\ .stride\ =\ gray.components\ ==\ 3\ ?\ gray.width\ :\ gray.bytesPerRow,\ .buf\ =\ grayBuf\ \}\;\n\n\ \ \ \ \ \ \ \ zarray_t\ *detections\ =\ apriltag_detector_detect(td,\ &im)\;\n\ \ \ \ \ \ \ \ int\ detectionCount\ =\ zarray_size(detections)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ detectionObjs\[detectionCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ detectionCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ apriltag_detection_t\ *det\;\n\ \ \ \ \ \ \ \ \ \ \ \ zarray_get(detections,\ i,\ &det)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ size\ =\ sqrt((det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])*(det->p\[0\]\[0\]\ -\ det->p\[1\]\[0\])\ +\ (det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\])*(det->p\[0\]\[1\]\ -\ det->p\[1\]\[1\]))\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ angle\ =\ atan2(-1\ *\ (det->p\[1\]\[1\]\ -\ det->p\[0\]\[1\]),\ det->p\[1\]\[0\]\ -\ det->p\[0\]\[0\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ detectionObjs\[i\]\ =\ Jim_ObjPrintf(\"id\ %d\ c\ \{%f\ %f\}\ p\ \{\{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\ \{%f\ %f\}\}\ size\ %d\ angle\ %f\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->id,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->c\[0\],\ det->c\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[0\]\[0\],\ det->p\[0\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[1\]\[0\],\ det->p\[1\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[2\]\[0\],\ det->p\[2\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ det->p\[3\]\[0\],\ det->p\[3\]\[1\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size,\ angle)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ zarray_destroy(detections)\;\n\ \ \ \ \ \ \ \ if\ (gray.components\ ==\ 3)\ free(grayBuf)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ result\ =\ Jim_NewListObj(interp,\ detectionObjs,\ detectionCount)\;\n\ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ detectCleanup\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\{TAG_FAMILY\}_destroy(tf)\;\n\ \ \ \ \ \ \ \ apriltag_detector_destroy(td)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ detector\ \[\$cc\ compile\]\n\ \ \ \ \$detector\ detectInit\n\ \ \ \ return\ \$detector\n\}\nClaim\ the\ AprilTag\ detector\ maker\ is\ \[fn\ makeAprilTagDetector\]\n\nset\ tagFamily\ \"tagStandard52h13\"\nset\ entireFrameDetector\ \[makeAprilTagDetector\ \$tagFamily\ 2.0\ 1\]\nset\ incrementalDetector\ \[makeAprilTagDetector\ \$tagFamily\ 1.5\ 1\]\n\n#\ Entire-frame\ tag\ detector:\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"entireFrameDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$entireFrameDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ \$this\ entire-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ entire-frame\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Incremental\ tag\ detector\ (looks\ at\ regions\ where\ there\ were\ tags\n#\ seen\ recently):\nWhen\ /nobody/\ wishes\ to\ calibrate\ camera\ /any/\ to\ display\ /any/\ /...etc/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ -serially\ camera\ /camera/\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTs/\ \{\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"incrementalDetect:\ \$frameTs\"\n\n\ \ \ \ try\ -signal\ \{\n\n\ \ \ \ #\ Query\ all\ the\ existing\ tag\ detections\ that\ are\ out\ there.\n\ \ \ \ #\ Find\ the\ most\ recent\ detection\ of\ each\ tag\;\ will\ use\ these\ to\n\ \ \ \ #\ give\ us\ regions\ of\ interest\ to\ do\ partial\ scans\ on\ the\ new\n\ \ \ \ #\ camera\ frame.\n\ \ \ \ set\ dets\ \[dict\ create\]\n\ \ \ \ ForEach!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$camera\ at\ timestamp\ /timestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\n\ \ \ \ \ \ \ \ #\ calibration.\ We\ exclude\ them\ from\ incremental\ detection\ so\n\ \ \ \ \ \ \ \ #\ it\ doesn't\ get\ hugely\ slow\ if\ you\ happen\ to\ leave\ a\n\ \ \ \ \ \ \ \ #\ calibration\ board\ out.\ (but\ this\ carve-out\ feels\ like\ it\n\ \ \ \ \ \ \ \ #\ weirdly\ cuts\ across\ an\ abstraction\ level)\n\ \ \ \ \ \ \ \ if\ \{\$id\ >=\ 48600\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ if\ \{(\[dict\ exists\ \$dets\ \$id\]\ &&\ \[dict\ get\ \$dets\ \$id\ timestamp\]\ <\ \$timestamp)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ !\[dict\ exists\ \$dets\ \$id\]\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ \$det\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ dets\ \$id\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ namespace\ import\ ::math::min\ ::math::max\n\ \ \ \ set\ tags\ \[list\]\n\ \ \ \ set\ frameWidth\ \[dict\ get\ \$frame\ width\]\n\ \ \ \ set\ frameHeight\ \[dict\ get\ \$frame\ height\]\n\ \ \ \ set\ aprilTime\ 0\n\ \ \ \ dict\ for\ \{id\ prevDet\}\ \$dets\ \{\n\ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$prevDet\ p\]\n\n\ \ \ \ \ \ \ \ set\ x\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y\ \$(floor(\[min\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\ \ \ \ \ \ \ \ set\ x1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 0\}\]\]))\n\ \ \ \ \ \ \ \ set\ y1\ \$(ceil(\[max\ \{*\}\[lmap\ corner\ \$corners\ \{lindex\ \$corner\ 1\}\]\]))\n\n\ \ \ \ \ \ \ \ set\ width\ \[-\ \$x1\ \$x\]\;\ set\ height\ \[-\ \$y1\ \$y\]\n\ \ \ \ \ \ \ \ set\ x\ \[max\ \[-\ \$x\ \$width\]\ 0\]\n\ \ \ \ \ \ \ \ set\ y\ \[max\ \[-\ \$y\ \$height\]\ 0\]\n\ \ \ \ \ \ \ \ set\ x1\ \[min\ \[+\ \$x1\ \$width\]\ \$frameWidth\]\n\ \ \ \ \ \ \ \ set\ y1\ \[min\ \[+\ \$y1\ \$height\]\ \$frameHeight\]\n\n\ \ \ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$frame\ \$x\ \$y\ \[-\ \$x1\ \$x\]\ \[-\ \$y1\ \$y\]\]\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[+\ \$aprilTime\ \[baretime\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ tag\ \[\$incrementalDetector\ detect\ \$subimage\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$c\ \[list\ \$x\ \$y\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[lmap\ corner\ \$p\ \{vec2\ add\ \$corner\ \[list\ \$x\ \$y\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tags\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \}\n\n\ \ \ \ Hold!\ -key\ \[list\ \$this\ incremental\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \[list\ \$this\ incremental\]\ detects\ tags\ \$tags\ on\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ at\ timestamp\ \$frameTs\ in\ time\ \$aprilTime\n\n\ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n\n#\ Integrate\ all\ the\ tag\ detections.\nWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \[list\ /someone/\ detects\ tags\ /tags/\ on\ camera\ /camera/\ \\\n\ \ \ \ \ \ \ \ \ at\ timestamp\ /timestamp/\ in\ time\ /aprilTime/\]\ are\ /results/\ \{\n\n\ \ \ \ set\ now\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ set\ latestTagDets\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ set\ timestamp\ \[dict\ get\ \$result\ timestamp\]\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ get\ \$result\ camera\]\n\ \ \ \ \ \ \ \ foreach\ tag\ \[dict\ get\ \$result\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ tag\ camera\ \$camera\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ tag\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$latestTagDets\ \$id\]\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$latestTagDets\ \$id\ timestamp\]\ <\ \$timestamp\}\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ latestTagDets\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ dict\ for\ \{id\ det\}\ \$latestTagDets\ \{\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ not\ immediately\ destroy\ the\ entire\ drawlist\ /\n\ \ \ \ \ \ \ \ #\ downstream\ statement\ set\ from\ the\ previous\ detection\ (give\n\ \ \ \ \ \ \ \ #\ the\ new\ detection\ some\ time\ to\ converge\ first).\n\ \ \ \ \ \ \ \ Claim\ -keep\ 8ms\ tag\ \$id\ has\ detection\ \$det\ on\ camera\ \[dict\ get\ \$det\ camera\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \[dict\ get\ \$det\ timestamp\]\n\ \ \ \ \}\n\ \ \ \ set\ aprilTime\ \[lmap\ r\ \$results\ \{dict\ get\ \$r\ aprilTime\}\]\n\ \ \ \ Claim\ the\ AprilTag\ time\ is\ \$aprilTime\n\}\n\n\}\n
<unknown> claims builtin-programs/demos.folk has program code {# Setting aside this tag space (45000 (
[ m9:0 (s23:0) ]
)<unknown> claims builtin-programs/demos.folk has program code {# Setting aside this tag space (45000 to 45050) for Folk Demo Booklet
Claim 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
Claim 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
Claim 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
Claim 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
Claim 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
Claim 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
Claim 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
Claim 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
Claim 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
}
<unknown> claims builtin-programs/errors.folk has program code {When /p/ has error /err/ with info /i (
[ m10:0 (s19:0) ]
)<unknown> claims builtin-programs/errors.folk has program code {When /p/ has error /err/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] == 1} {
Wish $p is outlined white
} else {
Wish $p is outlined red
}
}
Wish $p is titled $err
}
When /p/ has warning /w/ with info /info/ {
When the clock time is /t/ {
if {[expr {(int($t * 5)) % 2}] != 1} {
Wish $p is outlined yellow
}
}
Wish $p is titled $w
}
}
<unknown> claims builtin-programs/terminal.folk has program code #\ Terminal\n#\n#\ Spawn\ terminals\ (
[ m11:0 (s21:0) ]
)<unknown> claims builtin-programs/terminal.folk has program code #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n
<unknown> claims builtin-programs/shapes.folk has program code set\ shapes\ \[dict\ create\ triangle\ (
[ m12:0 (s29:0) ]
)<unknown> claims builtin-programs/shapes.folk has program code set\ shapes\ \[dict\ create\ triangle\ 3\ square\ 4\ pentagon\ 5\ hexagon\ 6\ septagon\ 7\ octagon\ 8\ nonagon\ 9\]\n\nproc\ process_offset\ \{offset\ region\}\ \{\n\ \ if\ \{!\[info\ exists\ region\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ set\ w\ \[region\ width\ \$region\]\n\ \ set\ h\ \[region\ height\ \$region\]\n\ \ \n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \n\ \ \ \ \ \ !\[string\ match\ *%*\ \$offset\]\ &&\ \n\ \ \ \ \ \ !\[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ return\ \$offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ simple\ percentage\ string:\ \"50%\"\n\ \ if\ \{\[string\ match\ *%*\ \$offset\]\ &&\ \[llength\ \$offset\]\ ==\ 1\}\ \{\n\ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$offset\]\ /\ 100.0\}\]\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \ #\ Default\ to\ horizontal\ offset\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ strings:\ \"right\",\ \"left\",\ \"up\",\ \"down\"\n\ \ if\ \{\$offset\ eq\ \"right\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"left\"\}\ \{\n\ \ \ \ return\ \[list\ \[expr\ \{-\$w\ *\ 0.5\}\]\ 0\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"up\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ 0.5\}\]\]\n\ \ \}\ elseif\ \{\$offset\ eq\ \"down\"\}\ \{\n\ \ \ \ return\ \[list\ 0\ \[expr\ \{\$h\ *\ 0.5\}\]\]\n\ \ \}\n\ \ \n\ \ #\ Handle\ directional\ percentage:\ \"right\ 50%\",\ \"left\ 25%\",\ etc.\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\ &&\ \[string\ is\ alpha\ -strict\ \[lindex\ \$offset\ 0\]\]\}\ \{\n\ \ \ \ set\ direction\ \[lindex\ \$offset\ 0\]\n\ \ \ \ set\ amount\ \[lindex\ \$offset\ 1\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$amount\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$amount\]\ /\ 100.0\}\]\n\n\ \ \ \ \ \ switch\ \$direction\ \{\n\ \ \ \ \ \ \ \ \"right\"\ \{\ return\ \[list\ \[expr\ \{\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"left\"\ \ \{\ return\ \[list\ \[expr\ \{-\$w\ *\ \$pct\}\]\ 0\]\ \}\n\ \ \ \ \ \ \ \ \"up\"\ \ \ \ \{\ return\ \[list\ 0\ \[expr\ \{-\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ \"down\"\ \ \{\ return\ \[list\ 0\ \[expr\ \{\$h\ *\ \$pct\}\]\]\ \}\n\ \ \ \ \ \ \ \ default\ \{\ return\ \[list\ 0\ 0\]\ \}\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\ \ \n\ \ #\ Handle\ x\ y\ vector\ where\ one\ or\ both\ components\ have\ percentage\ notation\n\ \ if\ \{\[llength\ \$offset\]\ ==\ 2\}\ \{\n\ \ \ \ lassign\ \$offset\ ox\ oy\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$ox\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$ox\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ ox\ \[expr\ \{\$w\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ match\ *%*\ \$oy\]\}\ \{\n\ \ \ \ \ \ set\ pct\ \[expr\ \{\[string\ map\ \{%\ \"\"\}\ \$oy\]\ /\ 100.0\}\]\n\ \ \ \ \ \ set\ oy\ \[expr\ \{\$h\ *\ \$pct\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ \[list\ \$ox\ \$oy\]\n\ \ \}\n\ \ \n\ \ #\ Default\ fallback\n\ \ return\ \$offset\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ shape\ with\ /...options/\ \{\n\ \ set\ isRect\ 0\n\ \ if\ \{\[dict\ exists\ \$options\ type\]\ &&\ \[dict\ get\ \$options\ type\]\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ isRect\ 1\n\ \ \}\n\ \ \n\ \ set\ c\ \[dict_getdef\ \$options\ center\ \{0\ 0\}\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 1\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ angle\ \[dict_getdef\ \$options\ angle\ 0\]\n\ \ \n\ \ if\ \{\$isRect\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ 100\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ 100\]\n\ \ \ \ \n\ \ \ \ set\ hw\ \[expr\ \{\$w\ /\ 2.0\}\]\n\ \ \ \ set\ hh\ \[expr\ \{\$h\ /\ 2.0\}\]\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \]\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \$v\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\ else\ \{\n\ \ \ \ set\ numPoints\ \[dict_getdef\ \$options\ sides\ 4\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ shape\]\ &&\ \[dict\ exists\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\}\ \{\n\ \ \ \ \ \ set\ numPoints\ \[dict\ get\ \$shapes\ \[dict\ get\ \$options\ shape\]\]\n\ \ \ \ \}\n\ \ \ \ set\ r\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ set\ points\ \{\{0\ 0\}\}\n\ \ \ \ set\ centerPoint\ \{0\ 0\}\n\ \ \ \ set\ polyAngle\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\ +\ 3.14159\}\]\n\ \ \ \ set\ angleIncr\ \[expr\ \{2\ *\ 3.14159\ /\ \$numPoints\}\]\n\ \ \ \ \n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$numPoints\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ set\ p\ \[vec2\ add\ \[lindex\ \$points\ end\]\ \[vec2\ scale\ \[list\ \[expr\ \{cos(\$polyAngle)\}\]\ \[expr\ \{sin(\$polyAngle)\}\]\]\ \$r\]\]\n\ \ \ \ \ \ lappend\ points\ \$p\n\ \ \ \ \ \ set\ centerPoint\ \[vec2\ add\ \$centerPoint\ \$p\]\n\ \ \ \ \ \ set\ polyAngle\ \[expr\ \{\$polyAngle\ +\ \$angleIncr\}\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ points\ \[lmap\ v\ \$points\ \{\n\ \ \ \ \ \ vec2\ add\ \[vec2\ rotate\ \[vec2\ sub\ \$v\ \[vec2\ scale\ \$centerPoint\ \[expr\ \{1.0/\$numPoints\}\]\]\]\ \$angle\]\ \$c\n\ \ \ \ \}\]\n\ \ \}\n\ \ \n\ \ if\ \{\$filled\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ color\ \$color\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$points\ width\ \$thickness\ color\ \$color\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ color\ white\n\}\n\n#\ Handle\ \"a\"\ vs\ \"an\"\ grammar\ variations\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ \ #\ As\ shapes.folk\ but\ for\ text.\n\ \ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ \ set\ pageAngle\ \[region\ angle\ \$r\]\n\n\ \ \ #\ Use\ the\ page's\ angle\ unless\ explicitly\ overwritten\n\ \ \ set\ defaults\ \[dict\ create\ \\\n\ \ \ \ \ \ \ color\ white\ \\\n\ \ \ \ \ \ \ scale\ 1.0\ \\\n\ \ \ \ \ \ \ layer\ 0\ \\\n\ \ \ \ \ \ \ angle\ \$pageAngle\ \\\n\ \ \ \ \ \ \ anchor\ center\ \\\n\ \ \ \ \ \ \ font\ \"PTSans-Regular\"\n\ \ \ \]\n\n\ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\n\ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ set\ scale\ \[dict\ get\ \$options\ scale\]\n\ \ \ set\ layer\ \[dict\ get\ \$options\ layer\]\n\ \ \ set\ angle\ \[dict\ get\ \$options\ angle\]\n\ \ \ set\ anchor\ \[dict\ get\ \$options\ anchor\]\n\ \ \ set\ font\ \[dict\ get\ \$options\ font\]\n\n\ \ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$pageAngle\]\]\n\n\ \ \ Wish\ to\ draw\ text\ with\ position\ \$center\ scale\ \$scale\ text\ \$text\\\n\ \ \ \ \ \ \ \ color\ \$color\ radians\ \$angle\ anchor\ \$anchor\ font\ \$font\n\}\ \n\nWhen\ /someone/\ wishes\ /p/\ draws\ text\ /text/\ \{\n\ \ \ \ Wish\ \$p\ draws\ text\ \$text\ with\ color\ white\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ \n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ false\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 5\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \n\ \ if\ \{\$shape\ eq\ \"circle\"\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$center\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\$shape\ eq\ \"rect\"\}\ \{\n\ \ \ \ set\ w\ \[dict_getdef\ \$options\ width\ \[region\ width\ \$r\]\]\n\ \ \ \ set\ h\ \[dict_getdef\ \$options\ height\ \[region\ height\ \$r\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ type\ rect\ center\ \$center\ width\ \$w\ height\ \$h\ angle\ \$angle\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ elseif\ \{\[dict\ exists\ \$shapes\ \$shape\]\}\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ \[dict\ get\ \$shapes\ \$shape\]\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \ \ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 50\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \$center\ radius\ \$radius\ \\\n\ \ \ \ \ \ angle\ \$angle\ color\ \$color\ filled\ \$filled\ thickness\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\n#\ Pass\ through\ options\ for\ \"an\"\ version\nWhen\ /someone/\ wishes\ /p/\ draws\ an\ /shape/\ with\ /...options/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ \{*\}\$options\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ rect\ with\ width\ /w/\ height\ /h/\ \{\n\ \ Wish\ \$p\ draws\ a\ rect\ with\ width\ \$w\ height\ \$h\n\}\n\nWhen\ /someone/\ wishes\ /p/\ draws\ a\ /shape/\ with\ radius\ /rad/\ \{\n\ \ Wish\ \$p\ draws\ a\ \$shape\ with\ radius\ \$rad\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ set\ of\ points\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ radius\ \[dict_getdef\ \$options\ radius\ 5\]\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ filled\ \[dict_getdef\ \$options\ filled\ true\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ set\ pointPos\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \ \ \n\ \ \ \ Wish\ to\ draw\ a\ circle\ with\ center\ \$pointPos\ radius\ \$radius\ thickness\ \$thickness\ \\\n\ \ \ \ \ \ color\ \$color\ filled\ \$filled\ layer\ \$layer\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ /page/\ draws\ a\ polyline\ /points/\ with\ /...options/\ &\ /page/\ has\ region\ /r/\ \{\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\ \ \n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ set\ center\ \[list\ \$cx\ \$cy\]\n\ \ \n\ \ if\ \{\[dict\ exists\ \$options\ offset\]\}\ \{\n\ \ \ \ set\ offset\ \[dict\ get\ \$options\ offset\]\n\ \ \ \ set\ offset\ \[process_offset\ \$offset\ \$r\]\n\ \ \ \ set\ center\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ set\ transformedPoints\ \{\}\n\ \ foreach\ point\ \$points\ \{\n\ \ \ \ lappend\ transformedPoints\ \[vec2\ add\ \$center\ \[vec2\ rotate\ \$point\ \$angle\]\]\n\ \ \}\n\ \ \n\ \ if\ \{\$dashed\}\ \{\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ \\\n\ \ \ \ \ \ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\ else\ \{\n\ \ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \$transformedPoints\ color\ \$color\ width\ \$thickness\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ Center\ circle\n\ \ Wish\ \$this\ draws\ a\ circle\n\ \ \n\ \ #\ Grid\ of\ shapes\ with\ varying\ thickness\n\ \ set\ baseX\ -850\n\ \ set\ baseY\ -200\n\ \ set\ gridSpacing\ 130\n\n\ \ #\ Row\ 0:\ Title\n\ \ Wish\ \$this\ draws\ text\ \"triangle\"\ with\ color\ skyblue\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"square\"\ with\ color\ green\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"pentagon\"\ with\ color\ gold\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ Wish\ \$this\ draws\ text\ \"hexagon\"\ with\ color\ orange\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ -\ (\$gridSpacing\ /\ 2.0)\}\]\]\ scale\ 0.9\ \n\ \ \n\ \ #\ Row\ 1:\ Regular\ polygons\ with\ different\ colors\ and\ thickness\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ thickness\ 2\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ thickness\ 4\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ thickness\ 6\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ thickness\ 8\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\}\]\]\n\ \ \n\ \ #\ Row\ 2:\ Filled\ shapes\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ color\ skyblue\ filled\ true\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ square\ with\ color\ green\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ color\ gold\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*2\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ color\ orange\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing*3\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing\}\]\]\n\n\ \ #\ Row\ 3:\ Directional\ offset\ examples\ (replacing\ shift)\n\ \ Wish\ \$this\ draws\ a\ triangle\ with\ radius\ 40\ offset\ \"right\ 50%\"\ color\ skyblue\n\ \ Wish\ \$this\ draws\ a\ square\ with\ radius\ 40\ offset\ \ \"left\ 50%\"\ color\ green\n\ \ Wish\ \$this\ draws\ a\ pentagon\ with\ radius\ 40\ offset\ \"up\ 50%\"\ color\ gold\n\ \ Wish\ \$this\ draws\ a\ hexagon\ with\ radius\ 40\ offset\ \"down\ 50%\"\ color\ orange\n\ \ \n\ \ #\ Row\ 4:\ Rectangles\ with\ different\ properties\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ cyan\ thickness\ 3\ offset\ \[list\ \$baseX\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ color\ magenta\ filled\ true\ offset\ \[list\ \[expr\ \{\$baseX\ +\ \$gridSpacing\}\]\ \[expr\ \{\$baseY\ +\ \$gridSpacing*3\}\]\]\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \"right\ 50%\"\n\ \ Wish\ \$this\ draws\ a\ rect\ with\ width\ 80\ height\ 50\ offset\ \ \"left\ 50%\"\n\ \ \n#\ Animated\ elements\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ angle\ \$r\]\ angle\n\ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 8\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ offsetVector\ \[list\ \[sin\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\ \[*\ 2\ \[cos\ \[+\ \[-\ \$i\ \$t\]\ \$angle\]\]\]\]\n\ \ \ \ \ \ \ \ \ \ set\ vector\ \[::vec2::scale\ \$offsetVector\ \[+\ \[*\ \$i\ \$i\]\ 15\]\]\n\ \ \ \ \ \ \ \ \ \ Wish\ \$this\ draws\ a\ circle\ with\ radius\ \$i\ color\ palegoldenrod\ offset\ \$vector\n\ \ \ \ \ \ \}\n\ \ \}\n\ \ \n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(sin(\$t)\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[-\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[-\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fillVal\"\ color\ red\n\ \ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ &\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n\ \ \ \ set\ fillVal\ \[expr\ \{round(\$t\ *\ 2)\}\]\n\ \ \ \ set\ fill\ \[expr\ \{\$fillVal\ %\ 2\ ==\ 0\}\]\n\ \ \ \ set\ y\ \[-\ \$y\ 150\]\n\ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 4\ center\ \[list\ \[+\ \$x\ 200\]\ \$y\]\ radius\ 60\ color\ white\ filled\ \$fill\n\ \ \ \ Wish\ to\ draw\ text\ with\ position\ \[list\ \[+\ \$x\ 200\]\ \[+\ \$y\ 14\]\]\ scale\ 1.5\ text\ \"\$fill\"\ color\ red\n\ \ \}\n\ \ \n\ \ Wish\ \$this\ is\ outlined\ white\n\}\n
<unknown> claims builtin-programs/intersect.folk has program code \nWhen\ /someone/\ wishes\ /p/\ has (
[ m13:0 (s27:0) ]
)<unknown> claims builtin-programs/intersect.folk has program code \nWhen\ /someone/\ wishes\ /p/\ has\ neighbors\ &\ /p/\ has\ region\ /r/\ &\ /p2/\ has\ region\ /r2/\ \{\n\ \ if\ \{\$p\ eq\ \$p2\}\ \{\ return\ \}\n\ \ lassign\ \[regionToBbox\ \$r\]\ bMinX\ bMinY\ bMaxX\ bMaxY\n\ \ lassign\ \[regionToBbox\ \$r2\]\ b2MinX\ b2MinY\ b2MaxX\ b2MaxY\n\ \ \n\ \ set\ hasIntersections\ \[rectanglesOverlap\ \[list\ \$bMinX\ \$bMinY\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$bMaxX\ \$bMaxY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MinX\ \$b2MinY\]\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$b2MaxX\ \$b2MaxY\]\\\n\ \ false\ \]\n\ \ #Display::stroke\ \[list\ \[list\ \$bMinX\ \$bMinY\]\ \{500\ 500\}\]\ 3\ blue\n\ \ #Display::stroke\ \[list\ \[list\ \$bMaxX\ \$bMaxY\]\ \{500\ 500\}\]\ 3\ red\n\n\ \ if\ \{\$hasIntersections\}\ \{\n\ \ \ \ Claim\ \$p\ has\ neighbor\ \$p2\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \{500\ 500\}\]\ 3\ red\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MaxX\ \$b2MaxY\]\ \{500\ 500\}\]\ 3\ white\n\ \ \ \ #Display::stroke\ \[list\ \[list\ \$b2MinX\ \$b2MinY\]\ \[list\ \$b2MaxX\ \$b2MaxY\]\]\ 10\ blue\n\ \ \}\n\}\n\nWhen\ when\ /p/\ has\ neighbor\ /n/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ Wish\ \$p\ has\ neighbors\n\}\n
<unknown> claims builtin-programs/regions.folk has program code {When when the distance between /p1/ (
[ m14:0 (s28:0) ]
)<unknown> claims builtin-programs/regions.folk has program code {When when the distance between /p1/ and /p2/ is /distanceVar/ /body/ with environment /e/ & /p1/ has region /r1/ & /p2/ has region /r2/ {
Claim the distance between $p1 and $p2 is [region distance $r1 $r2]
}
When /someone/ wishes region /r/ is /verbed/ /x/ {
Claim $r has region $r
Wish $r is $verbed $x
}
}
<unknown> claims builtin-programs/audio.folk has program code #\ Provides\ WAV,\ FLAC,\ and\ MP3\ fil (
[ m15:0 (s34:0) ]
)<unknown> claims builtin-programs/audio.folk has program code #\ Provides\ WAV,\ FLAC,\ and\ MP3\ file\ playback\ using\ the\ miniaudio\ library.\ Requires\n#\ ALSA,\ PulseAudio,\ or\ JACK\ drivers.\n#\n#\ See\ https://miniaud.io/.\ We\ are\ using\ Miniaudio\ v0.11.23.\n#\n#\ Examples:\n#\n#\ Play\ a\ sound\ file\ in\ assets/sounds/\ or\ user-programs/\$hostname/sounds:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ drums.wav\n#\n#\ Play\ a\ sound\ file\ by\ absolute\ path:\n#\n#\ \ \ \ Wish\ to\ play\ audio\ /home/folk/sounds/drums.wav\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/miniaudio\n\nif\ \{!\[catch\ \{exec\ which\ sclang\}\]\}\ \{\n\ \ \ \ #\ HACK:\ We're\ running\ msuic.folk\ and\ therefore\ are\ running\ JACK,\n\ \ \ \ #\ so\ we\ should\ force\ miniaudio\ to\ not\ use\ ALSA\ directly\ (because\n\ \ \ \ #\ that\ won't\ work).\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ MA_NO_ALSA\n\ \ \ \ \ \ \ \ #define\ MA_NO_PULSEAUDIO\n\ \ \ \ \}\n\}\n\$cc\ code\ \{\n\ \ \ #define\ MINIAUDIO_IMPLEMENTATION\n\}\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <stdint.h>\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <miniaudio.h>\n\nif\ \{\$::tcl_platform(os)\ ne\ \"Darwin\"\}\ \{\n\ \ \ \ \$cc\ endcflags\ -lpthread\ -lm\ -ldl\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ ma_context\ \ \ \ \ g_ctx\;\n\ \ \ \ static\ ma_engine\ \ \ \ \ \ g_engine\;\n\ \ \ \ static\ ma_sound_group\ g_group\;\n\n\ \ \ \ static\ bool\ g_ctx_initialized\ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_engine_initialized\ =\ false\;\n\ \ \ \ static\ bool\ g_engine_started\ \ \ \ \ =\ false\;\n\ \ \ \ static\ bool\ g_group_initialized\ \ =\ false\;\n\n\ \ \ \ static\ pthread_mutex_t\ g_state_mtx\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ typedef\ struct\ SoundNode\ \{\n\ \ \ \ \ \ \ \ ma_sound*\ \ \ \ \ \ \ \ \ snd\;\n\ \ \ \ \ \ \ \ struct\ SoundNode*\ next\;\n\ \ \ \ \}\ SoundNode\;\n\n\ \ \ \ static\ SoundNode*\ \ \ \ \ \ g_head\ \ \ \ \ \ \ \ \ \ \ \ =\ NULL\;\n\ \ \ \ static\ pthread_mutex_t\ g_list_mtx\ \ \ \ \ \ \ \ =\ PTHREAD_MUTEX_INITIALIZER\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ \ =\ false\;\n\ \ \ \ static\ pthread_t\ \ \ \ \ \ \ g_reaper_thr\;\n\ \ \ \ static\ bool\ \ \ \ \ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ /*\ Maintains\ linked\ list\ of\ active\ sounds\ */\n\ \ \ \ static\ bool\ registry_add(ma_sound*\ snd)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ (SoundNode*)malloc(sizeof\ *node)\;\n\n\ \ \ \ \ \ \ \ if\ (!node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ registry_add:\ alloc\ failed\\n\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ node->snd\ =\ snd\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ node->next\ =\ g_head\;\n\ \ \ \ \ \ \ \ g_head\ =\ node\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Removes\ and\ uninitializes\ all\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void\ registry_clear_locked(void)\ \{\n\ \ \ \ \ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ next\ =\ node->next\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (node->snd)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(node->snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(node)\;\n\ \ \ \ \ \ \ \ \ \ \ \ node\ =\ next\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ g_head\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Background\ thread\ that\ periodically\ removes\ finished\ sounds\ from\ the\ registry\ */\n\ \ \ \ static\ void*\ reaper_main(void*\ arg)\ \{\n\ \ \ \ \ \ \ \ (void)arg\;\n\n\ \ \ \ \ \ \ \ while\ (!g_shutdown_reaper)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ \ node\ \ =\ g_head\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound*\ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ remove\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (snd\ &&\ !ma_sound_is_playing(snd)\ &&\ !ma_sound_is_looping(snd))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Collect\ finished\ sounds\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remove\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (remove)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ SoundNode*\ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(to_free)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ usleep(50\ *\ 1000)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\ \ \ \ \ \ \ \ registry_clear_locked()\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ \ \ \ \ g_reaper_running\ =\ false\;\n\ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ static\ int\ reaper_start(void)\ \{\n\ \ \ \ \ \ \ \ if\ (g_reaper_running)\ return\ 0\;\n\ \ \ \ \ \ \ \ g_shutdown_reaper\ =\ false\;\n\n\ \ \ \ \ \ \ \ int\ err\ =\ pthread_create(&g_reaper_thr,\ NULL,\ reaper_main,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (err\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ g_reaper_running\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ err\;\n\ \ \ \ \}\n\n\ \ \ \ /*\ Initializes\ the\ audio\ backend\ and\ sound\ group,\ and\ starts\ the\ reaper\ thread\ */\n\ \ \ \ static\ bool\ audio_init_impl(void)\ \{\n\ \ \ \ \ \ \ \ ma_result\ r\;\n\n\ \ \ \ \ \ \ \ if\ (!g_ctx_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_context_init(NULL,\ 0,\ NULL,\ &g_ctx)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ context\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_ctx_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ma_engine_config\ cfg\ =\ ma_engine_config_init()\;\n\ \ \ \ \ \ \ \ \ \ \ \ cfg.pContext\ =\ &g_ctx\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_init(&cfg,\ &g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"miniaudio:\ engine\ initialized\ with\ %s\ backend\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_get_backend_name(g_ctx.backend))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_engine_started)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_engine_start(&g_engine)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ engine\ start\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (!g_group_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ r\ =\ ma_sound_group_init(&g_engine,\ 0,\ NULL,\ &g_group)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ group\ init\ failed:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\ (int)r)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ Unwind\ engine\ on\ group\ failure\;\ context\ remains\ for\ future\ attempts\ */\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (g_engine_initialized)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_engine_uninit(&g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memset(&g_engine,\ 0,\ sizeof\ g_engine)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_initialized\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g_engine_started\ =\ false\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ g_group_initialized\ =\ true\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ int\ err\ =\ reaper_start()\;\n\n\ \ \ \ \ \ \ \ if\ (err\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"audio:\ reaper\ thread\ create\ failed:\ %d\\n\",\ err)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ false\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ audioInit\ \{\}\ bool\ \{\n\ \ \ \ pthread_mutex_lock(&g_state_mtx)\;\n\ \ \ \ bool\ success\ =\ audio_init_impl()\;\n\ \ \ \ pthread_mutex_unlock(&g_state_mtx)\;\n\n\ \ \ \ if\ (success)\ \{\n\ \ \ \ \ \ \ \ return\ true\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ERROR(\"miniaudio:\ audio\ init\ failed\\n\")\;\n\ \ \ \ return\ false\;\n\}\n\n\$cc\ proc\ audioStop\ \{ma_sound*\ target\}\ void\ \{\n\ \ \ \ SoundNode*\ to_free\ =\ NULL\;\n\ \ \ \ ma_sound*\ snd\ =\ NULL\;\n\n\ \ \ \ pthread_mutex_lock(&g_list_mtx)\;\n\n\ \ \ \ SoundNode**\ pprev\ =\ &g_head\;\n\ \ \ \ SoundNode*\ node\ =\ g_head\;\n\n\ \ \ \ /*\ Find\ the\ sound\ to\ stop.\ TODO:\ this\ duplicates\ traversal\ logic\ from\ the\ reaper\ thread\ */\n\ \ \ \ while\ (node)\ \{\n\ \ \ \ \ \ \ \ if\ (node->snd\ ==\ target)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ snd\ =\ node->snd\;\n\ \ \ \ \ \ \ \ \ \ \ \ node->snd\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ *pprev\ =\ node->next\;\n\ \ \ \ \ \ \ \ \ \ \ \ to_free\ =\ node\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ pprev\ =\ &node->next\;\n\ \ \ \ \ \ \ \ node\ =\ node->next\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&g_list_mtx)\;\n\n\ \ \ \ /*\ Sound\ already\ reaped\ or\ never\ registered\ */\n\ \ \ \ if\ (!to_free)\ return\;\n\n\ \ \ \ if\ (snd)\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\ \ \ \ \ \ \ \ snd\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ free(to_free)\;\n\}\n\n\$cc\ proc\ playSound\ \{char*\ path\}\ ma_sound*\ \{\n\ \ \ \ ma_sound*\ snd\ =\ (ma_sound*)malloc(sizeof\ *snd)\;\n\n\ \ \ \ if\ (!snd)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ alloc\ sound\ failed\\n\")\;\n\ \ \ \ \}\n\n\ \ \ \ ma_result\ r\ =\ ma_sound_init_from_file(&g_engine,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MA_SOUND_FLAG_DECODE\ |\ MA_SOUND_FLAG_NO_SPATIALIZATION,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &g_group,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ init\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ r\ =\ ma_sound_start(snd)\;\n\n\ \ \ \ if\ (r\ !=\ MA_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ start\ failed\ for\ %s:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ path,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ma_result_description(r),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (int)r)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (!registry_add(snd))\ \{\n\ \ \ \ \ \ \ \ ma_sound_stop(snd)\;\n\ \ \ \ \ \ \ \ ma_sound_uninit(snd)\;\n\ \ \ \ \ \ \ \ free(snd)\;\n\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"miniaudio:\ playSound:\ registry\ add\ failed\ for\ %s\\n\",\ path)\;\n\ \ \ \ \}\n\n\ \ \ \ fprintf(stderr,\ \"miniaudio:\ playing\ %s\\n\",\ path)\;\n\ \ \ \ return\ snd\;\n\}\n\ntry\ \{\n\ \ \ \ set\ audioLib\ \[\$cc\ compile\]\n\ \ \ \ set\ success\ \[\$audioLib\ audioInit\]\n\n\ \ \ \ if\ \{!\$success\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ init\ failed\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ audio\ library\ is\ \$audioLib\n\}\ on\ error\ e\ \{\n\ \ \ \ puts\ stderr\ \"audio:\ compile\ failed:\ \$e\"\n\}\n\nWhen\ the\ audio\ library\ is\ /audioLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ play\ audio\ /sound/\ \{\n\n\ \ \ \ #\ Check\ if\ the\ sound\ file\ exists\ in\ the\ user-programs/\$hostname/sounds\ directory\n\ \ \ \ #\ or\ in\ the\ working\ directory's\ assets/sounds\ subdirectory.\ Otherwise,\ assume\n\ \ \ \ #\ it's\ an\ absolute\ path.\n\ \ \ \ proc\ resolveSoundPath\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ scriptDir\ \[file\ dirname\ \[info\ script\]\]\n\ \ \ \ \ \ \ \ set\ projectRoot\ \[pwd\]\n\ \ \ \ \ \ \ \ set\ hostname\ \[info\ hostname\]\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/user-programs/\$hostname/audio/\$filename\"\n\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ set\ path\ \"\$projectRoot/audio/\$filename\"\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \$path\]\}\ \{\ return\ \$path\ \}\n\n\ \ \ \ \ \ \ \ #\ treat\ as\ an\ absolute\ path\n\ \ \ \ \ \ \ \ return\ \$filename\n\ \ \ \ \}\n\n\ \ \ \ set\ path\ \[resolveSoundPath\ \$sound\]\n\n\ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ File\ not\ found\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ handle\ \[\$audioLib\ playSound\ \$path\]\n\n\ \ \ \ if\ \{\$handle\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"audio:\ Failed\ to\ play\ '\$path'\"\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ puts\ \"audio:\ stopping\ audio\ '\$path'\"\n\ \ \ \ \ \ \ \ \$audioLib\ audioStop\ \$handle\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/sprites.folk has program code ########\n#\ Could\ extend\ this\ to\ (
[ m16:0 (s32:0) ]
)<unknown> claims builtin-programs/sprites.folk has program code ########\n#\ Could\ extend\ this\ to\ draw\ from\ camera\ with:\n#\ \ \ Wish\ \$this\ has\ thumbnail\ grid\ with\ 8\ frames\ and\ 4\ columns\n#\ \ \ When\ \$this\ has\ thumbnail\ grid\ /thumbnails/\ \{\n#\ \ \ \ \ Wish\ \$this\ draws\ \$thumbnails\;\ #\ Would\ need\ to\ query\ \$thumnails\ for\ its\ frameCount\ and\ columns\n#\ \ \ \}\n#######\n\n#\ -\ path\ get\ prepended\ with\ ~/folk-images/\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /anyone/\ wishes\ /p/\ draws\ sprite\ /path/\ with\ /...options/\ \{\n\n\ \ set\ frames\ \[dict\ get\ \$options\ frames\]\n\ \ set\ columns\ \[dict\ get\ \$options\ columns\]\n\ \ set\ fps\ \[dict\ getdef\ \$options\ fps\ 60\]\n\n\ \ fn\ loadImage\n\ \ set\ im\ \[loadImage\ \$path\]\n\n\ \ set\ sheetWidth\ \[\$imageLib\ Image_width\ \$im\]\n\ \ set\ sheetHeight\ \[\$imageLib\ Image_height\ \$im\]\n\ \ set\ spriteWidth\ \[/\ \$sheetWidth\ \$columns\]\n\ \ set\ rows\ \[/\ \$frames\ \$columns\]\n\ \ set\ spriteHeight\ \[/\ \$sheetHeight\ \$rows\]\n\n\ \ When\ -atomicallyWithKey\ \[list\ sprite\ \$p\ \$path\]\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ set\ frameNumber\ \[expr\ \{round\ (\$t\ *\ \$fps)\ %\ \$frames\}\]\n\ \ \ \ \ \ set\ x\ \[expr\ \{(\$frameNumber\ %\ \$columns)\ *\ \$spriteWidth\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{(\$frameNumber\ %\ \$rows)\ *\ \$spriteHeight\}\]\n\n\ \ \ \ \ \ set\ subimage\ \[\$imageLib\ slice\ \$im\ \$x\ \$y\ \$spriteWidth\ \$spriteHeight\]\n\ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$subimage\ with\ \{*\}\$options\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ Wish\ \$this\ draws\ sprite\ \$path\ with\ 8\ frames\ and\ 4\ columns\n\}\n
<unknown> claims builtin-programs/keyboard.folk has program code #\ Function\ to\ check\ if\ the\ dev (
[ m17:0 (s35:0) ]
)<unknown> claims builtin-programs/keyboard.folk has program code #\ Function\ to\ check\ if\ the\ device\ is\ a\ keyboard\nproc\ isKeyboard\ \{device\}\ \{\n\ \ \ \ set\ properties\ \[exec\ udevadm\ info\ --query=property\ --name=\$device\]\n\ \ \ \ if\ \{\$properties\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ return\ false\n\ \ \ \ \}\n\ \ \ \ set\ isKeyboard\ \[string\ match\ *ID_INPUT_KEYBOARD=1*\ \$properties\]\n\ \ \ \ return\ \$isKeyboard\n\ \ \ \ #\ TODO:\ Excluding\ mice\ would\ nice\ to\ keey\ the\ list\ of\ keyboard\ devices\ short\n\ \ \ \ #\ \ \ \ \ \ \ Alas,\ including\ mice\ is\ necessary\ for\ the\ Logitech\ K400R\ keyboard\n\ \ \ \ #\ set\ isMouse\ \[string\ match\ *ID_INPUT_MOUSE=1*\ \$properties\]\n\ \ \ \ #\ return\ \[expr\ \{\$isKeyboard\ &&\ !\$isMouse\}\]\n\}\n\n####\n#\ /dev/input/event*\ addresses\ are\ the\ ground\ truth\ for\ keyboard\ devices\n#\n#\ This\ function\ goes\ through\ each\ of\ them\ and\ checks\ if\ they\ are\ keyboards\nproc\ walkInputEventPaths\ \{\}\ \{\n\ \ \ \ #\ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/event*\"\]\n\ \ \ \ set\ allDevices\ \[glob\ -nocomplain\ \"/dev/input/by-path/*\"\]\n\ \ \ \ set\ keyboards\ \[list\]\n\ \ \ \ foreach\ device\ \$allDevices\ \{\n\ \ \ \ \ \ \ \ if\ \{\[isKeyboard\ \$device\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[file\ readable\ \$device\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"keyboard:\ Device\ \$device\ is\ not\ readable.\ Attempting\ to\ change\ permissions.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Attempt\ to\ change\ permissions\ so\ that\ the\ file\ can\ be\ read\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ chmod\ +r\ \$device\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ keyboards\ \$device\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$keyboards\n\}\n\nset\ keyboardDevices\ \[walkInputEventPaths\]\nforeach\ keyboard\ \$keyboardDevices\ \{\n\ \ \ \ Claim\ \$keyboard\ is\ a\ keyboard\ device\n\}\n\n#\ backwards\ compatibility\nWhen\ /page/\ is\ a\ keyboard\ with\ path\ /keyboard/\ \{\n\ \ \ \ Claim\ \$page\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ us\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ device\ \{\n\ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ set\ defaultKeymap\ \[keymap\ load\ us\]\n\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ include\ <linux/input.h>\n\ \ \ \ \$cc\ include\ <sys/ioctl.h>\n\ \ \ \ \$cc\ include\ <stdio.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\n\ \ \ \ #\ This\ needs\ to\ be\ called\ on\ this\ thread\ (since\ it\ depends\ on\n\ \ \ \ #\ interpreter-local\ information\ about\ the\ channel),\ and\ then\ the\n\ \ \ \ #\ returned\ fileno\ is\ portable\ to\ other\ threads\ which\ can\ do\ the\n\ \ \ \ #\ keyboard\ grab/ungrab\ later.\n\ \ \ \ \$cc\ proc\ getFileno\ \{Jim_Interp*\ interp\ Jim_Obj*\ channel\}\ int\ \{\n\ \ \ \ \ \ \ \ int\ fd\ =\ Jim_AioFilehandle(interp,\ channel)\;\n\ \ \ \ \ \ \ \ if\ (fd\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"unable\ to\ open\ channel\ '%s'\ as\ file\\n'\",\ Jim_String(channel))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ fd\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ setGrabDevice\ \{Jim_Interp*\ interp\ int\ fileno\ bool\ grab\}\ void\ \{\n\ \ \ \ \ \ \ \ ioctl(fileno,\ EVIOCGRAB,\ (void*)grab)\;\n\ \ \ \ \}\n\n\ \ \ \ set\ grabber\ \[\$cc\ compile\]\n\n\ \ \ \ set\ KEY_STATES\ \[list\ up\ down\ repeat\]\n\n\ \ \ \ set\ keyboardChannel\ \[open\ \$keyboard\ r\]\n\ \ \ \ fconfigure\ \$keyboardChannel\ -translation\ binary\n\n\ \ \ \ set\ keyboardFileno\ \[\$grabber\ getFileno\ \$keyboardChannel\]\n\ \ \ \ #\ \$grabber\ setGrabDevice\ \$keyboardFileno\ 1\n\n\ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \[dict\ create\]\n\n\ \ \ \ When\ /page/\ is\ a\ keyboard\ with\ path\ \$keyboard\ locale\ /locale/\ \{\n\ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$localKeymaps\ \$locale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{!\[exists\ -command\ keymap\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ source\ \"lib/keymap.tcl\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ map\ \[keymap\ load\ \$locale\]\n\ \ \ \ \ \ \ \ dict\ set\ localKeymaps\ \$locale\ \$map\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ TODO:\ do\ this\ removal\ (it's\ slow\ and\ happens\ even\ when\ we\n\ \ \ \ \ \ \ \ #\ blink\ out,\ causing\ cascading\ slowness,\ so\ skipping\ for\ now)\n\n\ \ \ \ \ \ \ \ #\ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ #\ \ \ \ \ dict\ unset\ localKeymaps\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ Hold!\ \[list\ local-keymaps\ \$keyboard\]\ \\\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \ \ \ \ Claim\ \$keyboard\ has\ keymaps\ \$localKeymaps\n\n\ \ \ \ \ \ \ \ #\ \ \ \ \ #\ keymap\ destroy\ \$map\n\ \ \ \ \ \ \ \ #\ \ \ \ \ \$grabber\ setGrabDevice\ \$keyboardFileno\ \[dict\ size\ \$localKeymaps\]\n\ \ \ \ \ \ \ \ #\ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ evtBytes\ 16\n\ \ \ \ set\ evtFormat\ iissi\n\ \ \ \ if\ \{\[exec\ getconf\ LONG_BIT\]\ ==\ 64\}\ \{\n\ \ \ \ \ \ \ \ set\ evtBytes\ 24\n\ \ \ \ \ \ \ \ set\ evtFormat\ wwssi\n\ \ \ \ \}\n\n\ \ \ \ set\ modifiers\ \$::keymap::modWeights\n\ \ \ \ foreach\ k\ \[dict\ keys\ \$modifiers\]\ \{\n\ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$k\ 0\n\ \ \ \ \}\n\ \ \ \ while\ 1\ \{\n\ \ \ \ \ \ \ \ binary\ scan\ \[read\ \$keyboardChannel\ \$evtBytes\]\ \$evtFormat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ tvSec\ tvUsec\ type\ code\ value\n\n\ \ \ \ \ \ \ \ if\ \{\$type\ ==\ 0x01\}\ \{\ \;#\ EV_KEY\n\ \ \ \ \ \ \ \ \ \ \ \ set\ localKeymaps\ \[QueryOne!\ \$keyboard\ has\ keymaps\ /./\ -default\ \{\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ values\ \$localKeymaps\]\ activeKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$activeKeymap\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ activeKeymap\ \$defaultKeymap\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mods\ \[+\ \{*\}\[dict\ values\ \$modifiers\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[keymap\ resolve\ \$activeKeymap\ \$code\ \$mods\]\ key\ keychar\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$key\ eq\ \"\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ keyState\ \[lindex\ \$KEY_STATES\ \$value\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isDown\ \[expr\ \{\$keyState\ !=\ \"up\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$::keymap::modWeights\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ weight\ \[dict\ get\ \$::keymap::modWeights\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ modifiers\ \$key\ \[expr\ \{\$isDown\ *\ \$weight\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ now\ \$(\[clock\ milliseconds\]\ /\ 1000.0)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ create\ timestamp\ \$now\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$mods\ &\ 1\}\ \{\ dict\ set\ options\ shift\ 1\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modKeyNotHeld\ \[expr\ \{\$mods\ <=\ 1\}\]\ \;#\ excluding\ Shift\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keychar\ ne\ \"\"\ &&\ \$modKeyNotHeld\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printable\ \$keychar\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ keyboard\ \$keyboard\ claims\ key\ \$key\ is\ \$keyState\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/collect.folk has program code When\ when\ the\ collected\ results\ (
[ m18:0 (s37:0) ]
)<unknown> claims builtin-programs/collect.folk has program code When\ when\ the\ collected\ results\ for\ /clause/\ are\ /resultsVar/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ to\ collect\ results\ for\ \$clause\ with\ settle\ 0ms\n\}\nWhen\ when\ the\ collected\ results\ for\ /clause/\ with\ settle\ /settle/\ are\ /resultsVar/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ to\ collect\ results\ for\ \$clause\ with\ settle\ \$settle\n\}\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I.\n\$cc\ include\ <string.h>\n\$cc\ include\ <pthread.h>\n\$cc\ include\ \"trie.h\"\n\$cc\ include\ \"db.h\"\n\$cc\ code\ \{\n\ \ \ \ extern\ Db*\ db\;\n\ \ \ \ extern\ Clause*\ jimObjToClause(Jim_Interp*\ interp,\ Jim_Obj*\ obj)\;\n\ \ \ \ extern\ Statement*\ HoldStatementGlobally(const\ char\ *key,\ double\ version,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Clause\ *clause,\ long\ keepMs,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *destructorCode,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *sourceFileName,\ int\ sourceLineNumber)\;\n\ \ \ \ extern\ Statement*\ HoldStatementGloballyAcquiring(const\ char\ *key,\ double\ version,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Clause\ *clause,\ long\ keepMs,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *destructorCode,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ char\ *sourceFileName,\ int\ sourceLineNumber)\;\n\ \ \ \ extern\ Clause*\ claimizeClause(Clause*\ clause)\;\n\n\ \ \ \ typedef\ struct\ EnvironmentBinding\ \{\n\ \ \ \ \ \ \ \ char\ name\[100\]\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ value\;\n\ \ \ \ \}\ EnvironmentBinding\;\n\ \ \ \ typedef\ struct\ Environment\ \{\n\ \ \ \ \ \ \ \ int\ nBindings\;\n\ \ \ \ \ \ \ \ EnvironmentBinding\ bindings\[\]\;\n\ \ \ \ \}\ Environment\;\n\ \ \ \ extern\ Environment*\ clauseUnify(Jim_Interp*\ interp,\ Clause*\ a,\ Clause*\ b)\;\n\n\ \ \ \ typedef\ struct\ Collect\ \{\n\ \ \ \ \ \ \ \ char*\ _Atomic\ patternStr\;\n\ \ \ \ \ \ \ \ uint64_t\ _Atomic\ collectAtTime\;\n\ \ \ \ \}\ Collect\;\n\n\ \ \ \ #define\ COLLECTS_MAX\ 1000\n\ \ \ \ Collect\ collects\[COLLECTS_MAX\]\;\n\ \ \ \ pthread_mutex_t\ collectsMutex\;\n\n\ \ \ \ static\ int64_t\ timestamp_get(clockid_t\ clk_id)\ \{\n\ \ \ \ \ \ \ \ //\ Returns\ timestamp\ in\ nanoseconds.\n\ \ \ \ \ \ \ \ struct\ timespec\ ts\;\n\ \ \ \ \ \ \ \ if\ (clock_gettime(clk_id,\ &ts))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ perror(\"can't\ even\ get\ the\ time\ :'-(\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ (int64_t)ts.tv_sec\ *\ 1000000000\ +\ (int64_t)ts.tv_nsec\;\n\ \ \ \ \}\n\n\ \ \ \ char*\ makeCollectKey(Jim_Obj*\ patternObj)\ \{\n\ \ \ \ \ \ \ \ const\ char\ COLLECT\[\]\ =\ \"collect\ \"\;\n\ \ \ \ \ \ \ \ int\ collectLen\ =\ sizeof(COLLECT)\ -\ 1\;\n\n\ \ \ \ \ \ \ \ int\ keyLen\ =\ Jim_Length(patternObj)\;\n\ \ \ \ \ \ \ \ char\ *collectKey\ =\ malloc(collectLen\ +\ keyLen\ +\ 1)\;\n\ \ \ \ \ \ \ \ memcpy(collectKey,\ COLLECT,\ collectLen)\;\n\ \ \ \ \ \ \ \ memcpy(collectKey\ +\ collectLen,\ Jim_String(patternObj),\ keyLen\ +\ 1)\;\n\ \ \ \ \ \ \ \ return\ collectKey\;\n\ \ \ \ \}\n\n\ \ \ \ Term*\ jimObjToTerm(Jim_Obj*\ obj)\ \{\n\ \ \ \ \ \ \ \ int\ len\;\ const\ char*\ s\;\n\ \ \ \ \ \ \ \ s\ =\ Jim_GetString(obj,\ &len)\;\n\ \ \ \ \ \ \ \ return\ termNew(s,\ len)\;\n\ \ \ \ \}\n\n\ \ \ \ int\ _Atomic\ version\ =\ 0\;\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_init(&collectsMutex,\ NULL)\;\n\}\n\$cc\ proc\ Recollect!\ \{Jim_Obj*\ patternObj\ bool\ isAtomically\}\ void\ \{\n\ \ \ \ //\ First,\ query\ for\ collect\ patterns.\n\ \ \ \ Clause*\ collectorPattern\ =\ clauseNew(10)\;\n\ \ \ \ collectorPattern->terms\[0\]\ =\ termNew(\"/someone/\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[1\]\ =\ termNew(\"wishes\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[2\]\ =\ termNew(\"to\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[3\]\ =\ termNew(\"collect\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[4\]\ =\ termNew(\"results\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[5\]\ =\ termNew(\"for\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[6\]\ =\ jimObjToTerm(patternObj)\;\n\ \ \ \ collectorPattern->terms\[7\]\ =\ termNew(\"with\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[8\]\ =\ termNew(\"settle\",\ -1)\;\n\ \ \ \ collectorPattern->terms\[9\]\ =\ termNew(\"/settle/\",\ -1)\;\n\n\ \ \ \ char*\ collectKey\ =\ makeCollectKey(patternObj)\;\n\n\ \ \ \ ResultSet*\ collectorsSet\ =\ dbQuery(db,\ collectorPattern)\;\n\ \ \ \ if\ (collectorsSet->nResults\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Clause*\ emptyClause\ =\ clauseNew(0)\;\n\ \ \ \ \ \ \ \ HoldStatementGlobally(collectKey,\ version++,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emptyClause,\ 0,\ NULL,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(interp,\ patternObj)\;\n\n\ \ \ \ \ \ \ \ ResultSet*\ rs\ =\ dbQuery(db,\ pattern)\;\n\ \ \ \ \ \ \ \ size_t\ unclaimizedNResults\ =\ rs->nResults\;\n\n\ \ \ \ \ \ \ \ Clause*\ claimizedPattern\ =\ claimizeClause(pattern)\;\n\ \ \ \ \ \ \ \ if\ (claimizedPattern\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ResultSet*\ rs1\ =\ dbQuery(db,\ claimizedPattern)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ rs\ =\ realloc(rs,\ SIZEOF_RESULTSET(rs->nResults\ +\ rs1->nResults))\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ rs1->nResults\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rs->results\[rs->nResults\ +\ i\]\ =\ rs1->results\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ rs->nResults\ +=\ rs1->nResults\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(rs1)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Now\ acquire\ all\ the\ statements\ in\ rs,\ unify\ each\ statement's\n\ \ \ \ \ \ \ \ //\ clause\ with\ the\ pattern,\ and\ build\ up\ a\ results\ Jim\ object.\n\n\ \ \ \ \ \ \ \ Statement**\ resultStmts\ =\ malloc(sizeof(Statement*)\ *\ rs->nResults)\;\n\ \ \ \ \ \ \ \ int\ resultStmtsCount\ =\ 0\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultsObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ rs->nResults\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Statement*\ result\ =\ statementAcquire(db,\ rs->results\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (result\ ==\ NULL)\ \{\ continue\;\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ If\ `isAtomically`\ is\ on,\ then\ throw\ away\ any\n\ \ \ \ \ \ \ \ \ \ \ \ //\ statement\ that\ has\ an\ AtomicallyVersion\ _and_\ that\n\ \ \ \ \ \ \ \ \ \ \ \ //\ AtomicallyVersion\ isn't\ converged\ yet.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isAtomically\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementAtomicallyVersion(result)\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ !dbAtomicallyVersionHasConverged(statementAtomicallyVersion(result)))\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ fprintf(stderr,\ \"DISCARD\ %.100s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ clauseToString(statementClause(result)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ result)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ resultStmts\[resultStmtsCount++\]\ =\ result\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Environment*\ env\ =\ clauseUnify(interp,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i\ >=\ unclaimizedNResults\ ?\ claimizedPattern\ :\ pattern,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementClause(result))\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ envDict\[env->nBindings\ *\ 2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ env->nBindings\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ envDict\[j*2\]\ =\ Jim_NewStringObj(interp,\ env->bindings\[j\].name,\ -1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ envDict\[j*2+1\]\ =\ env->bindings\[j\].value\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *resultObj\ =\ Jim_NewDictObj(interp,\ envDict,\ env->nBindings\ *\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ resultsObj,\ resultObj)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(env)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (claimizedPattern\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(claimizedPattern)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ clauseFree(pattern)\;\n\ \ \ \ \ \ \ \ free(rs)\;\n\n\ \ \ \ \ \ \ \ //\ Note\ that\ at\ this\ point,\ we've\ still\ acquired\ all\ the\n\ \ \ \ \ \ \ \ //\ statements\ in\ rs.\ We\ need\ to\ hang\ onto\ them\ to\ inherit\n\ \ \ \ \ \ \ \ //\ their\ destructors.\n\n\ \ \ \ \ \ \ \ Clause*\ collectedClause\ =\ clauseNew(9)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[0\]\ =\ termNew(\"builtin-programs/collect.folk\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[1\]\ =\ termNew(\"claims\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[2\]\ =\ termNew(\"the\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[3\]\ =\ termNew(\"collected\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[4\]\ =\ termNew(\"results\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[5\]\ =\ termNew(\"for\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[6\]\ =\ jimObjToTerm(patternObj)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[7\]\ =\ termNew(\"are\",\ -1)\;\n\ \ \ \ \ \ \ \ collectedClause->terms\[8\]\ =\ jimObjToTerm(resultsObj)\;\n\ \ \ \ \ \ \ \ Jim_DecrRefCount(interp,\ resultsObj)\;\n\n\ \ \ \ \ \ \ \ Statement*\ stmt\ =\n\ \ \ \ \ \ \ \ \ \ \ \ HoldStatementGloballyAcquiring(collectKey,\ version++,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ collectedClause,\ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ Now\ inherit\ the\ destructors\ of\ all\ the\ statements\ in\ rs\n\ \ \ \ \ \ \ \ //\ into\ the\ new\ collection\ statement,\ and\ release\ all\ the\n\ \ \ \ \ \ \ \ //\ statements\ in\ rs.\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultStmtsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (stmt\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ statementInheritDestructors(stmt,\ resultStmts\[i\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ FIXME:\ what\ to\ do\ if\ stmt\ is\ NULL?\n\n\ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ resultStmts\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ free(resultStmts)\;\n\n\ \ \ \ \ \ \ \ if\ (stmt\ !=\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dbInflightDecr(db,\ stmt)\;\n\ \ \ \ \ \ \ \ \ \ \ \ statementRelease(db,\ stmt)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ free(collectKey)\;\n\ \ \ \ clauseFree(collectorPattern)\;\n\ \ \ \ free(collectorsSet)\;\n\}\n#\ If\ the\ recollect\ doesn't\ have\ a\ settle\ time,\ we\ should\ recollect\n#\ immediately.\ If\ the\ recollect\ has\ a\ settle\ time,\ then\ we\ should\ bump\n#\ its\ next\ occurrence\ forward\ by\ the\ settle\ time.\n\$cc\ proc\ ScheduleRecollect!\ \{Jim_Obj*\ patternObj\ uint64_t\ settle\}\ void\ \{\n\ \ \ \ if\ (settle\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Recollect_(patternObj,\ false)\;\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ uint64_t\ now\ =\ timestamp_get(CLOCK_MONOTONIC)\;\n\ \ \ \ char*\ patternStr\ =\ strdup(Jim_String(patternObj))\;\n\n\ \ \ \ pthread_mutex_lock(&collectsMutex)\;\n\n\ \ \ \ int\ i\;\n\ \ \ \ for\ (i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ strcmp(collects\[i\].patternStr,\ patternStr)\ ==\ 0)\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ now\ +\ settle\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(patternStr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (i\ <\ COLLECTS_MAX)\ \{\ goto\ done\;\ \}\n\n\ \ \ \ for\ (i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].patternStr\ =\ patternStr\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ now\ +\ settle\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(i\ <\ COLLECTS_MAX)\;\n\n\ done:\n\ \ \ \ pthread_mutex_unlock(&collectsMutex)\;\n\}\n\$cc\ proc\ RunScheduledRecollects!\ \{\}\ void\ \{\n\ \ \ \ uint64_t\ now\ =\ timestamp_get(CLOCK_MONOTONIC)\;\n\n\ \ \ \ pthread_mutex_lock(&collectsMutex)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ COLLECTS_MAX\;\ i++)\ \{\n\ \ \ \ \ \ \ \ if\ (collects\[i\].patternStr\ !=\ NULL\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ <=\ now)\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ Recollect_(Jim_NewStringObj(interp,\ collects\[i\].patternStr,\ -1),\ true)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ free(collects\[i\].patternStr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].patternStr\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ collects\[i\].collectAtTime\ =\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&collectsMutex)\;\n\}\nset\ collectLib\ \[\$cc\ compile\]\n\$collectLib\ init\n\n#\ FIXME:\ If\ there's\ not\ settlement\ for\ a\ while,\ we\ should\ just\ take\n#\ whatever\ we\ can\ get.\n\n#\ FIXME:\ If\ we're\ just\ booting\ now,\ we\ should\ sample\ whatever's\ in\n#\ place\ already.\n\nWhen\ /someone/\ wishes\ to\ collect\ results\ for\ /pattern/\ with\ settle\ /settle/\ \{\n\ \ \ \ if\ \{\[string\ match\ \{*ms\}\ \$settle\]\}\ \{\n\ \ \ \ \ \ \ \ set\ settleMs\ \[string\ range\ \$settle\ 0\ end-2\]\n\ \ \ \ \ \ \ \ set\ settleNs\ \[*\ \$settleMs\ 1000000\]\n\ \ \ \ \}\n\ \ \ \ When\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\n\ \ \ \ \ \ \ \ On\ unmatch\ \[list\ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\]\n\ \ \ \ \}\n\ \ \ \ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\n\ \ \ \ On\ unmatch\ \[list\ \$collectLib\ ScheduleRecollect!\ \$pattern\ \$settleNs\]\n\}\n\nWhen\ the\ internal\ time\ is\ /t/\ \{\n\ \ \ \ \$collectLib\ RunScheduledRecollects!\n\}\n
<unknown> claims builtin-programs/title.folk has program code #\ Title/footnote\ wish\ fulfillment\n# (
[ m20:0 (s44:0) ]
)<unknown> claims builtin-programs/title.folk has program code #\ Title/footnote\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ Wish\ \$this\ is\ titled\ \"This\ is\ a\ tag\"\n#\ Wish\ \$this\ is\ footnoted\ \"This\ is\ a\ footnote\"\n#\ Wish\ \$this\ is\ right-margined\ \"This\ is\ right-margined\ text\"\n#\ Wish\ \$this\ is\ left-margined\ \"This\ is\ left-margined\ text\"\n\nWhen\ /thing/\ has\ quad\ /quad/\ \{\n\ \ \ \ Claim\ -keep\ 50ms\ \$thing\ has\ a\ quad\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ /thing/\ has\ a\ quad\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ foreach\ \{label\ edge\ textAnchor\}\ \{\n\ \ \ \ \ \ \ \ titled\ \ \ \ \ \ \ \ \ top\ \ \ \ bottom\n\ \ \ \ \ \ \ \ footnoted\ \ \ \ \ \ bottom\ top\n\ \ \ \ \ \ \ \ right-margined\ right\ \ left\n\ \ \ \ \ \ \ \ left-margined\ \ left\ \ \ right\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ wishes\ \$thing\ is\ \$label\ /text/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ text\ \[join\ \[lmap\ result\ \$results\ \{dict\ get\ \$result\ text\}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$text\ eq\ \"\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -atomicallyWithKey\ \[list\ \$thing\ quad\ \$label\]\ \$thing\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::unitLengthVector\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$quadLib\ vertices\ \[quadChange\ \$q\ \"display\ \$disp\"\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft\ topRight\ bottomRight\ bottomLeft\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$edge\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$topRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$bottomLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$bottomLeft\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$bottomLeft\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topRight\ \$bottomRight\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topRight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[scale\ 0.5\ \[add\ \$topLeft\ \$bottomLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalDir\ \[sub\ \$topLeft\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ paddingMeters\ 0.02\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ offset\ \[scale\ \$paddingMeters\ \[unitLengthVector\ \$physicalDir\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ physicalPos\ \[add\ \$physicalPos\ \$offset\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispPosition\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$physicalPos\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopLeft\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTopRight\ \[\$poseLib\ project\ \$displayIntrinsics\ \$displayWidth\ \$displayHeight\ \$topRight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispTop\ \[vec2\ sub\ \$dispTopRight\ \$dispTopLeft\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRadians\ \[expr\ \{-atan2(\[lindex\ \$dispTop\ 1\],\ \[lindex\ \$dispTop\ 0\])\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position\ \$dispPosition\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scale\ 36.0\ radians\ \$dispRadians\ anchor\ \$textAnchor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text\ \$text\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/esc-pos.folk has program code When\ the\ print\ library\ is\ /print (
[ m21:0 (s41:0) ]
)<unknown> claims builtin-programs/esc-pos.folk has program code When\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\n\n\ \ \ \ fn\ printProgram\ \{printer\ id\ code\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ writeFolkFile\ \$id\ \$code\n\ \ \ \ \ \ \ \ writeMetaFile\ \$printer\ \$id\n\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ is\ at\ /address/\n\ \ \ \ \ \ \ \ set\ printerSocket\ \[socket\ stream\ \$\{address\}:9100\]\n\n\ \ \ \ \ \ \ \ fconfigure\ \$printerSocket\ -translation\ binary\ -buffering\ none\n\ \ \ \ \ \ \ \ set\ template\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \[init\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[tag\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\])\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 2\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \[feed\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ \[cut\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$printerSocket\ \[render\ \$template\]\n\ \ \ \ \ \ \ \ close\ \$printerSocket\n\ \ \ \ \}\n\n\ \ \ \ fn\ render\ \{template\}\ \{\n\ \ \ \ \ \ \ \ set\ trimmed\ \[lmap\ line\ \[split\ \$template\ \"\\n\"\]\ \{\ string\ trim\ \$line\ \}\]\n\ \ \ \ \ \ \ \ set\ singleLine\ \[join\ \$trimmed\ \"\"\]\n\ \ \ \ \ \ \ \ return\ \[uplevel\ \[list\ subst\ \$singleLine\]\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeFolkFile\ \{id\ code\}\ \{\n\ \ \ \ \ \ \ \ set\ folkFile\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$folkFile\ \$code\n\ \ \ \ \ \ \ \ close\ \$folkFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ writeMetaFile\ \{printer\ id\}\ \{\n\ \ \ \ \ \ \ \ Expect!\ \$printer\ has\ tag\ geometry\ /geometry/\n\ \ \ \ \ \ \ \ set\ metaFile\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ \ \ \ \ puts\ \$metaFile\ \[subst\ \{Claim\ tag\ \\\$this\ has\ geometry\ \{\$geometry\}\}\]\n\ \ \ \ \ \ \ \ close\ \$metaFile\n\ \ \ \ \}\n\n\ \ \ \ fn\ cut\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1dV\\x0\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ feed\ n\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"\\x1b\\x64%c\"\ \$n\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ init\ \{\}\ \{\n\ \ \ \ \ \ \ \ return\ \"\\x1b\\x40\"\n\ \ \ \ \}\n\n\ \ \ \ fn\ raw\ number\ \{\n\ \ \ \ \ \ \ \ return\ \[format\ \"%c\"\ \$number\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ scaledAprilTag\ \{id\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ \ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\ \}\ \{\$i\ <\ \$scale\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \[expr\ \{\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ !=\ 255\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \{*\}\[lrepeat\ \$scale\ \$bit\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$tagBits\n\ \ \ \ \}\n\n\ \ \ \ #\ scale\ must\ be\ divisible\ by\ 4\ so\ width\ will\ be\ divisible\ by\ 8\n\ \ \ \ fn\ tag\ \{id\ \{scale\ 12\}\}\ \{\n\ \ \ \ \ \ \ \ set\ tagBits\ \[scaledAprilTag\ \$id\ \$scale\]\n\n\ \ \ \ \ \ \ \ set\ width\ \[expr\ \{10\ *\ \$scale\}\]\n\ \ \ \ \ \ \ \ set\ xL\ \[expr\ \{\$width\ /\ 8\}\]\ \ \ \;#\ width\ in\ bytes\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yL\ \[expr\ \{\$width\ %\ 256\}\]\ \;#\ height\ in\ lines\ (low\ byte)\n\ \ \ \ \ \ \ \ set\ yH\ \[expr\ \{\$width\ /\ 256\}\]\ \;#\ height\ in\ lines\ (high\ byte)\n\n\ \ \ \ \ \ \ \ return\ \"\\x1dv0\\x03\[raw\ \$xL\]\\x00\[raw\ \$yL\]\[raw\ \$yH\]\[binary\ format\ B*\ \[join\ \$tagBits\ \"\"\]\]\"\n\ \ \ \ \}\n\n\ \ \ \ Subscribe:\ print\ program\ /id/\ on\ receipt\ printer\ /printer/\ with\ code\ /code/\ \{\n\ \ \ \ \ \ \ \ printProgram\ \$printer\ \$id\ \$code\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/tags-geometry.folk has program code When\ the\ default\ program\ ge (
[ m22:0 (s43:0) ]
)<unknown> claims builtin-programs/tags-geometry.folk has program code When\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ program\ /program/\ is\ scaled\ by\ x\ /xScale/\ y\ /yScale/\ \{\n\ \ \ \ proc\ extractMm\ \{mm\}\ \{\n\ \ \ \ \ \ \ \ regexp\ \{(\[0-9.\]+)mm\}\ \$mm\ ->\ extracted\n\ \ \ \ \ \ \ \ return\ \$extracted\n\ \ \ \ \}\n\n\ \ \ \ set\ tagSize\ \[extractMm\ \[dict\ get\ \$defaultGeom\ tagSize\]\]\n\ \ \ \ set\ left\ \[extractMm\ \[dict\ get\ \$defaultGeom\ left\]\]\n\ \ \ \ set\ right\ \[extractMm\ \[dict\ get\ \$defaultGeom\ right\]\]\n\ \ \ \ set\ top\ \[extractMm\ \[dict\ get\ \$defaultGeom\ top\]\]\n\ \ \ \ set\ bottom\ \[extractMm\ \[dict\ get\ \$defaultGeom\ bottom\]\]\n\n\ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\n\ \ \ \ set\ right\ \$(\$right\ +\ (\$width\ *\ \$xScale\ -\ \$width))mm\n\ \ \ \ set\ bottom\ \$(\$bottom\ +\ (\$height\ *\ \$yScale\ -\ \$height))mm\n\n\ \ \ \ set\ newGeom\ \[list\ tagSize\ \$\{tagSize\}mm\ left\ \$\{left\}mm\ right\ \$\{right\}mm\ top\ \$\{top\}mm\ bottom\ \$\{bottom\}mm\]\n\n\ \ \ \ Claim\ tag\ \$program\ has\ geometry\ \$newGeom\n\}\n\nWhen\ the\ default\ program\ geometry\ is\ /defaultGeom/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /tag/\ has\ resolved\ geometry\ \{\n\n\ \ \ \ #\ Setting\ aside\ this\ tag\ space\ (48600\ to\ 48713)\ for\ calibration.\n\ \ \ \ if\ \{!(\$tag\ >=\ 0\ &&\ \$tag\ <\ 48600)\}\ \{\ return\ \}\n\n\ \ \ \ When\ the\ collected\ results\ for\ \[list\ /someone/\ claims\ tag\ \$tag\ has\ geometry\ /geom/\]\ are\ /results/\ \{\n\ \ \ \ \ \ \ \ #\ Choose\ a\ geometry.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \$defaultGeom\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"tags-to-quads:\ WARNING:\ Multiple\ geometries\ for\ \$tag\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ dim\ \{x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[expr\ \{\[string\ map\ \{mm\ \"\"\}\ \$x\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$geom\ \{\ dict\ set\ geom\ \$k\ \[dim\ \$v\]\ \}\n\ \ \ \ \ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[expr\ \{\$left\ +\ \$tagSize\ +\ \$right\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[expr\ \{\$top\ +\ \$tagSize\ +\ \$bottom\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ dict\ set\ geom\ width\ \$width\n\ \ \ \ \ \ \ \ dict\ set\ geom\ height\ \$height\n\ \ \ \ \ \ \ \ #\ This\ (resolved\ geometry)\ feels\ like\ a\ hack.\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ resolved\ geometry\ \$geom\n\n\ \ \ \ \ \ \ \ #\ Use\ the\ geometry\ to\ create\ the\ canvas\ projection,\n\ \ \ \ \ \ \ \ #\ which\ maps\ from\ page-space\ (in\ meters\ from\ the\ top-left\n\ \ \ \ \ \ \ \ #\ corner)\ to\ normalized-space\ (x\ and\ y\ from\ -1\ to\ 1)\n\ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ projection\ \$proj\n\n\ \ \ \ \ \ \ \ set\ writableTextureId\ \[list\ \$tag\ canvas\]\n\ \ \ \ \ \ \ \ #\ TODO:\ Set\ canvas\ resolution\ based\ on\ physical\ width\n\ \ \ \ \ \ \ \ #\ &\ height.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 40ms\ the\ GPU\ creates\ canvas\ \$writableTextureId\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1024\ height\ 1024\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$writableTextureId\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$tag\ has\ canvas\ \$writableTextureId\ with\ \{*\}\$opts\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/keyboard-shortcuts.folk has program code {# When sudo is removed in (
[ m23:0 (s46:0) ]
)<unknown> claims builtin-programs/keyboard-shortcuts.folk has program code {# When sudo is removed in the exec commands below you get:
# Error in builtin-programs/keyboard-shortcuts.folk, match m10029:6: Failed to restart folk.service: Interactive authentication required.
#
# TODO: Figure out how to do this with less powerful permissions than `sudo`. (@cwervo)
# Keyboard shortcuts
# ---
# Alt + Esc: Restart Folk
# Alt + F1: Stop Folk completely (note: need to ssh to restart Folk)
# Alt-Esc on most keyboards
Subscribe: keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
}
# Console_1 corresponds to Alt-F1 on most keyboards
Subscribe: keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
}
}
<unknown> claims builtin-programs/terminal-ui.folk has program code {# Manage terminal UI for Folk.
(
[ m29:0 (s54:0) ]
)<unknown> claims builtin-programs/terminal-ui.folk has program code {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}
<unknown> claims builtin-programs/connections.folk has program code #\ Connection\ wish\ fulfillment\ (
[ m33:0 (s67:0) ]
)<unknown> claims builtin-programs/connections.folk has program code #\ Connection\ wish\ fulfillment\n#\ for\ wishes\ of\ the\ form:\n#\ \"Wish\ \$tag\ is\ connected\ to\ \$tag2\"\ or\ \"Wish\ \$tag\ is\ dynamically\ connected\ to\ \$tag2\"\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ \{\n\ \ \ \ Wish\ \$source\ is\ dynamically\ connected\ to\ \$sink\ from\ centroid\ to\ centroid\n\}\n\nWhen\ /anyone/\ wishes\ /source/\ is\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ sub\ \$sink\ \$source\]\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ grey\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ set\ c\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 2\ color\ \$color\ layer\ \$layer\n\ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ 30\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\}\n\nset\ speed\ 75\nset\ spacing\ 50\nset\ maxsize\ 25\n\nWhen\ /anyone/\ wishes\ /source/\ is\ dynamically\ connected\ to\ /sink/\ /...options/\ &\ \\\n\ \ /source/\ has\ region\ /source_region/\ &\ \\\n\ \ /sink/\ has\ region\ /sink_region/\ \{\n\n\ \ \ if\ \{\$source\ ==\ \$sink\}\ \{return\}\n\n\ \ \ set\ p1\ \[dict_getdef\ \$options\ from\ centroid\]\n\ \ \ set\ p2\ \[dict_getdef\ \$options\ to\ centroid\]\n\ \ \ set\ source\ \[region\ \$p1\ \$source_region\]\n\ \ \ set\ sink\ \[region\ \$p2\ \$sink_region\]\n\n\ \ \ set\ direction\ \[vec2\ normalize\ \[vec2\ sub\ \$sink\ \$source\]\]\n\ \ \ set\ distance\ \[vec2\ distance\ \$sink\ \$source\]\n\ \ \ set\ angle\ \[expr\ \{atan2(-\[lindex\ \$direction\ 1\],\ \[lindex\ \$direction\ 0\])\ -\ 3.14159/2\}\]\ \n\n\ \ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ lassign\ \[vec2\ scale\ \[vec2\ add\ \$source\ \$sink\]\ 0.5\]\ cx\ cy\n\n\ \ \ Wish\ to\ draw\ a\ stroke\ with\ points\ \[list\ \$source\ \$sink\]\ width\ 1\ color\ \$color\ layer\ \$layer\n\ \ \ \n\ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ set\ offset\ \[expr\ \{round(\$t*\$speed)\ %\ \$spacing\}\]\n\ \ \ \ \ set\ count\ \[expr\ \{round(\$distance\ /\ \$spacing)\}\]\n\n\ \ \ \ \ for\ \{set\ p\ \$offset\}\ \{\$p\ <\ \$distance\}\ \{incr\ p\ \$spacing\}\ \{\n\ \ \ \ \ \ \ \ set\ c\ \[vec2\ add\ \$source\ \[vec2\ scale\ \$direction\ \$p\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[expr\ \{min(\$maxsize,\ 0.20*min(\$p,\ \$distance\ -\ \$p))\}\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ shape\ with\ sides\ 3\ center\ \$c\ radius\ \$s\ radians\ \$angle\ color\ \$color\ filled\ true\ layer\ \$layer\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/unix-commands.folk has program code #\ Spawns\ a\ Unix\ command\ to (
[ m47:0 (s77:0) ]
)<unknown> claims builtin-programs/unix-commands.folk has program code #\ Spawns\ a\ Unix\ command\ to\ stream\ output\ lines\ back\ to\ the\ Wisher.\n#\n#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ Wish\ \$this\ runs\ Unix\ command\ \"journalctl\"\ with\ arguments\ \[list\ \"-f\"\ \"-u\"\ \"folk\"\]\nWhen\ /someone/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ with\ arguments\ /args/\ \{\n\tset\ outputKeyName\ \[list\ unix-output\ \$p\]\n\tset\ errorKeyName\ \[list\ unix-error\ \$p\]\n\tset\ maxLines\ 500\n\tset\ maxLinesEndIndex\ \[expr\ \{\$maxLines\ -\ 1\}\]\n\tset\ accumulatedLines\ \[list\]\n\n\t#\ Bound\ how\ many\ lines\ we\ drain\ per\ tick\ to\ avoid\ starvation\ under\ heavy\ output\n\tset\ maxLinesPerTick\ 10\n\n\t#\ Build\ argv\ as\ a\ flat\ list\ and\ form\ pipeline\ tokens\n\tset\ flatArgs\ \[concat\ \{*\}\$args\]\n\tset\ argv\ \[list\ \$command\ \{*\}\$flatArgs\]\n\tset\ pipeline\ \[linsert\ \$argv\ 0\ |\]\n\n\ttry\ \{\n\t\t#\ Start\ the\ process\ with\ STDERR\ merged\ into\ STDOUT\n\t\tlappend\ pipeline\ 2>@1\n\t\tset\ fd\ \[open\ \$pipeline\ r\]\n\n\t\tfconfigure\ \$fd\ -blocking\ 0\ -buffering\ none\n\n\t\tset\ pids\ \[pid\ \$fd\]\n\t\tset\ pid\ \[lindex\ \$pids\ end\]\n\t\}\ on\ error\ e\ \{\n\t\tputs\ \"Failed\ to\ open\ '\$command':\ \$e\"\n\n\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$e\n\n\t\treturn\n\t\}\n\n\tOn\ unmatch\ \[list\ apply\ \{\{fd\ pid\}\ \{\n\t\tcatch\ \{close\ \$fd\}\n\t\tcatch\ \{kill\ SIGTERM\ \$pid\}\n\t\tafter\ 500\n\t\tcatch\ \{kill\ SIGKILL\ \$pid\}\n\t\}\ \}\ \$fd\ \$pid\]\n\n\twhile\ true\ \{\n\t\tset\ newLines\ \[list\]\n\t\tset\ drained\ 0\n\n\t\twhile\ \{\$drained\ <\ \$maxLinesPerTick\}\ \{\n\t\t\tset\ num\ \[gets\ \$fd\ line\]\n\t\t\tif\ \{\$num\ <\ 0\}\ \{\ break\ \}\n\n\t\t\tlappend\ newLines\ \$line\n\t\t\tincr\ drained\n\t\t\}\n\n\t\tif\ \{\[llength\ \$newLines\]\ >\ 0\}\ \{\n\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \$newLines\]\n\t\t\tset\ length\ \[llength\ \$accumulatedLines\]\n\n\t\t\tif\ \{\$length\ >\ \$maxLines\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[lrange\ \$accumulatedLines\ end-\$maxLinesEndIndex\ end\]\n\t\t\t\}\n\n\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\}\n\n\t\tif\ \{\[eof\ \$fd\]\}\ \{\n\t\t\t#\ Emit\ any\ last\ partial\ unterminated\ lines\n\t\t\tset\ tail\ \[read\ \$fd\]\n\n\t\t\tif\ \{\$tail\ ne\ \"\"\}\ \{\n\t\t\t\tset\ accumulatedLines\ \[concat\ \$accumulatedLines\ \[list\ \$tail\]\]\n\n\t\t\t\tHold!\ -key\ \$outputKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ output\ lines\ \$accumulatedLines\n\t\t\t\}\n\n\t\t\tif\ \{\[catch\ \{close\ \$fd\}\ err\]\}\ \{\n\t\t\t\tputs\ \"Close\ error\ for\ '\$command':\ \$err\"\n\n\t\t\t\tHold!\ -key\ \$errorKeyName\ \\\n\t\t\t\t\tClaim\ \$p\ has\ Unix\ error\ output\ \$err\n\t\t\t\}\n\n\t\t\tbreak\n\t\t\}\n\n\t\t#\ Sleep\ for\ a\ bit\ to\ avoid\ starving\ under\ heavy\ output\n\t\tafter\ 100\n\t\}\n\}\n\n#\ Convenience\ wrapper\ for\ commands\ without\ arguments\nWhen\ /wisher/\ wishes\ /p/\ runs\ Unix\ command\ /command/\ \{\n\tSay\ \$wisher\ wishes\ \$p\ runs\ Unix\ command\ \$command\ with\ arguments\ \[list\]\n\}\n\n#\ When\ /someone/\ wishes\ /p/\ tests\ Unix\ commands\ \{\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"echo\"\ with\ arguments\ \[list\ \"Hello\"\ \"World\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"curl\"\ with\ arguments\ \[list\ \"-fsS\"\ \"http://wttr.in/Baltimore?format='%l:+%C'\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"-sSh\"\ \"/home/folk/folk2\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ping\"\ with\ arguments\ \[list\ \"google.com\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"sh\"\ with\ arguments\ \[list\ \"-c\"\ \"while\ :\;\ do\ date\ +%s.%3N\;\ sleep\ 0.5\;\ done\"\]\n\n#\ \t#\ Test\ error\ handling:\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"ls\"\ with\ arguments\ \[list\ \"/nonexistent/path\"\]\n#\ \t#\ Wish\ \$p\ runs\ Unix\ command\ \"exec\"\ with\ arguments\ \[list\ \"/dev/null\"\]\n\n#\ \tWhen\ \$p\ has\ Unix\ error\ output\ /errorSummary/\ \{\n#\ \t\tputs\ \"errorSummary:\ \$errorSummary\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$errorSummary\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ red\n#\ \t\}\n\n#\ \tWhen\ \$p\ has\ Unix\ output\ lines\ /outputLines/\ \{\n#\ \t\tputs\ \"outputLines:\ \$outputLines\"\n\n#\ \t\tWish\ \$p\ is\ labelled\ \[join\ \$outputLines\ \"\\n\"\]\n#\ \t\tWish\ \$p\ is\ outlined\ green\n#\ \t\}\n#\ \}
<unknown> claims builtin-programs/editor-control.folk has program code When\ /page/\ has\ editor\ cod (
[ m50:0 (s82:0) ]
)<unknown> claims builtin-programs/editor-control.folk has program code When\ /page/\ has\ editor\ code\ /editorCode/\ &\ /page/\ has\ program\ code\ /programCode/\ \{\n\ \ \ \ Claim\ \$page\ has\ base64\ editor\ code\ \[binary\ encode\ base64\ \$editorCode\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ program\ code\ \[binary\ encode\ base64\ \$programCode\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \"/editor-control\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ html\ \{\n<!DOCTYPE\ html>\n<html\ lang=\"en\">\n\ \ \ \ <head>\n\ \ \ \ \ \ \ \ <meta\ charset=\"utf-8\"\ />\n\ \ \ \ \ \ \ \ <title>Editor\ copy/paste</title>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ </head>\n\ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ \ \ \ \ Select\ a\ keyboard:\ <select\ id=\"keyboard-select\"></select>\n\ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"120\"\ rows=\"40\"></textarea>\n\ \ \ \ \ \ \ \ <script>\nconst\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\nconst\ keyboardSelect\ =\ document.querySelector(\"#keyboard-select\")\;\nconst\ textarea\ =\ document.querySelector(\"#code\")\;\n\nvar\ currentKeyboard\ =\ null\;\nvar\ programCode\ =\ \"\"\;\ //\ not\ the\ same\ as\ editor\ code\nvar\ cursorPosition\ =\ \[0,\ 0\]\;\n\n//\ temporarily\ disable\ event\ processing\ after\ sending\ new\ code\ to\ prevent\ recursive\ event\ sends\nvar\ allowLocalEventsToProcess\ =\ true\;\nvar\ allowRemoteEventsToProcess\ =\ true\;\nvar\ _remoteTimoutHandle\;\nvar\ _localTimeoutHandle\;\nfunction\ disableRemoteEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_remoteTimoutHandle)\ clearTimeout(_remoteTimoutHandle)\;\n\ \ \ \ allowRemoteEventsToProcess\ =\ false\;\n\n\ \ \ \ _remoteTimoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowRemoteEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ disableLocalEventProcessing(durationMs)\ \{\n\ \ \ \ if\ (_localTimeoutHandle)\ clearTimeout(_localTimeoutHandle)\;\n\ \ \ \ allowLocalEventsToProcess\ =\ false\;\n\n\ \ \ \ _localTimeoutHandle\ =\ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ \ \ allowLocalEventsToProcess\ =\ true\;\n\ \ \ \ \},\ durationMs)\;\n\}\n\nfunction\ updateProgramCode()\ \{\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ currentCode\ =\ textarea.value\;\n\ \ \ \ programCode\ =\ currentCode\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{cursorPosition\[0\]\}\ \$\{cursorPosition\[1\]\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(currentCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\nfunction\ updateCursorAndCode(ev)\ \{\n\ \ \ \ if\ (!allowLocalEventsToProcess)\ return\;\n\ \ \ \ disableRemoteEventProcessing(500)\;\n\n\ \ \ \ const\ \{\ page,\ kbPath\ \}\ =\ currentKeyboard\;\n\n\ \ \ \ const\ newCode\ =\ ev.target.value\;\n\n\ \ \ \ //\ figure\ out\ cursor\ position\n\ \ \ \ const\ currentPosition\ =\ textarea.selectionStart\;\n\ \ \ \ const\ linesBefore\ =\ newCode.substring(0,\ currentPosition).split(\"\\n\")\;\n\ \ \ \ const\ y\ =\ linesBefore.length\ -\ 1\;\n\ \ \ \ const\ x\ =\ linesBefore\[linesBefore.length\ -\ 1\].length\;\n\n\ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ ws.run(tcl`\n\ \ \ \ \ \ \ \ Hold\ (non-capturing)\ (on\ builtin-programs/editor.folk)\ \$\{\"cursor\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ \$\{kbPath\}\ cursor\ is\ \[list\ \$\{x\}\ \$\{y\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Hold\ (on\ builtin-programs/editor.folk)\ \$\{\"code\"\ +\ kbPath\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(programCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$\{id\}\ has\ editor\ code\ \[binary\ decode\ base64\ \$\{btoa(newCode)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ `)\;\n\}\n\ntextarea.addEventListener(\"input\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"selectionchange\",\ updateCursorAndCode)\;\ntextarea.addEventListener(\"keydown\",\ ev\ =>\ \{\n\ \ \ \ if(ev.keyCode\ ===\ 83\ /*\ s\ */\ &&\ (navigator.platform.match(\"Mac\")\ ?\ ev.metaKey\ :\ ev.ctrlKey))\ \{\n\ \ \ \ \ \ \ \ ev.preventDefault()\;\n\ \ \ \ \ \ \ \ updateProgramCode()\;\n\ \ \ \ \}\n\})\;\n\nvar\ lastKeyboard\;\ //\ to\ clean\ up\ the\ previous\ keyboard\ when\ another\ is\ picked\nasync\ function\ selectKeyboard(\{\ page,\ kbPath\ \})\ \{\n\ \ \ \ if\ (lastKeyboard)\ lastKeyboard.stop()\;\n\n\ \ \ \ currentKeyboard\ =\ \{\ page,\ kbPath\ \}\;\n\n\ \ \ \ const\ id\ =\ page\ +\ kbPath\;\n\ \ \ \ lastKeyboard\ =\ await\ ws.watch(`\$\{id\}\ has\ base64\ editor\ code\ /editorCode/\ program\ code\ /programCode/\ &\ the\ \$\{kbPath\}\ cursor\ is\ /cursor/`,\ \{\n\ \ \ \ \ \ \ \ add:\ (\{\ editorCode,\ programCode:\ _programCode,\ cursor\ \})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (!allowRemoteEventsToProcess)\ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ disableLocalEventProcessing(500)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ programCode\ =\ atob(_programCode)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ editorCode\ =\ atob(editorCode)\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.value\ =\ editorCode\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ figure\ out\ where\ the\ cursor\ is\n\ \ \ \ \ \ \ \ \ \ \ \ let\ \[x,\ y\]\ =\ loadList(cursor)\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ parseInt(x)\;\ y\ =\ parseInt(y)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ cursorPosition\ =\ \[x,\ y\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ const\ lines\ =\ editorCode.split(\"\\n\")\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ let\ pos\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (let\ i\ =\ 0\;\ i\ <\ y\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ lines\[i\].length\ +\ 1\;\ //\ +\ 1\ for\ newline\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ x\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.focus()\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionStart\ =\ pos\;\n\ \ \ \ \ \ \ \ \ \ \ \ textarea.selectionEnd\ =\ pos\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \})\;\n\}\n\n//\ update\ keyboard\ list\ as\ it\ changes\nws.watchCollected(\"/page/\ is\ an\ editor\ &\ /page/\ is\ a\ keyboard\ with\ path\ /kbPath/\",\ keyboards\ =>\ \{\n\ \ \ \ keyboardSelect.innerHTML\ =\ \"\"\;\n\n\ \ \ \ for\ (let\ keyboard\ of\ keyboards)\ \{\n\ \ \ \ \ \ \ \ let\ \{page,\ kbPath\}\ =\ keyboard\;\n\ \ \ \ \ \ \ \ keyboardSelect.innerHTML\ +=\ `<option\ value=\"\$\{JSON.stringify(keyboard)\}\">\$\{page\}\ (\$\{kbPath\})</option>`\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (keyboards.length\ ===\ 1)\ \{\n\ \ \ \ \ \ \ \ selectKeyboard(keyboards\[0\])\;\n\ \ \ \ \}\n\})\;\n\n//\ fired\ when\ selected\ keyboard\ changes\nkeyboardSelect.addEventListener(\"input\",\ (ev)\ =>\ \{\n\ \ \ \ selectKeyboard(JSON.parse(ev.target.value))\;\n\})\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ </body>\n</html>\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/fswatch.folk has program code #\ Watch\ for\ builtin-programs/\ cha (
[ m52:0 (s81:0) ]
)<unknown> claims builtin-programs/fswatch.folk has program code #\ Watch\ for\ builtin-programs/\ changes.\ntry\ \{\n\ \ \ \ set\ fd\ \[open\ \[list\ |fswatch\ --recursive\ --event\ Updated\ --event\ Created\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ builtin-programs\ \$::env(HOME)/folk-data/local-program\ \$::env(PWD)/user-programs\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -buffering\ line\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ if\ \{\[gets\ \$fd\ line\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"fswatch:\ fswatch\ failed.\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{builtin-programs\\/.*\$\}\ \$line\ changedPath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ changedPath\ \$line\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ changedFilename\ \[file\ tail\ \$changedPath\]\n\ \ \ \ \ \ \ \ if\ \{\[string\ index\ \$changedFilename\ 0\]\ eq\ \".\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$changedFilename\ 0\]\ eq\ \"#\"\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[file\ extension\ \$changedFilename\]\ ne\ \".folk\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ \"fswatch:\ \$changedPath\ updated,\ ignoring.\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"fswatch:\ \$changedPath\ updated,\ reloading.\"\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$changedPath\ r\]\;\ set\ programCode\ \[read\ \$fp\]\;\ close\ \$fp\n\n\ \ \ \ \ \ \ \ Hold!\ -keep\ 100ms\ -on\ boot.folk\ -key\ \[list\ \$changedPath\ code\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$changedPath\ has\ program\ code\ \$programCode\n\ \ \ \ \}\n\}\ on\ error\ err\ \{\n\ \ \ \ puts\ stderr\ \"fswatch:\ Warning:\ could\ not\ invoke\ `fswatch`\ (\$err).\"\n\ \ \ \ puts\ stderr\ \"fswatch:\ Will\ not\ watch\ builtin-programs\ for\ changes.\"\n\}\n
<unknown> claims builtin-programs/display-saver.folk has program code When\ tag\ /nobody/\ has\ a\ pr (
[ m53:0 (s84:0) ]
)<unknown> claims builtin-programs/display-saver.folk has program code When\ tag\ /nobody/\ has\ a\ program\ &\ /nobody/\ has\ a\ display\ saver\ &\ \\\n\ \ \ \ \ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ puts\ \"Starting\ display-saver\"\n\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ set\ cy\ \[*\ \$displayHeight\ 0.3\]\n\ \ \ \ set\ host\ \[info\ hostname\]\n\ \ \ \ set\ msg\ \"Welcome\ to\ Folk\\n\$host\"\n\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ \\\n\ \ \ \ \ \ \ \ y\ \$cy\ \\\n\ \ \ \ \ \ \ \ text\ \$msg\ \\\n\ \ \ \ \ \ \ \ color\ green\ \\\n\ \ \ \ \ \ \ \ scale\ 80\n\n\tset\ borderPoints\ \[list\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ 0\]\ \\\n\t\ \ \ \ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ \$displayHeight\]\ \\\n\t\ \ \ \ \[list\ 0\ 0\]\]\n\n\tWish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$borderPoints\ width\ 6\ color\ white\n\}\n
<unknown> claims builtin-programs/draw/image.folk has program code When\ the\ jpeg\ library\ is\ /jpe (
[ m57:0 (s89:0) ]
)<unknown> claims builtin-programs/draw/image.folk has program code When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ fn\ jpegLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*jpg\"\ \$im\]\ ||\ \[string\ match\ \"*jpeg\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$jpegLib\ loadJpeg\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ jpegLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ png\ library\ is\ /pngLib/\ \{\n\ \ \ \ fn\ pngLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*png\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[\$pngLib\ loadPng\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ pngLoader\]\ is\ an\ image\ loader\n\}\n\nWhen\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ \ \ fn\ gifLoader\ \{im\}\ \{\n\ \ \ \ \ \ \ \ upvar\ coerceToImage\ coerceToImage\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gif\ \[\$gifLib\ loadGif\ \$im\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$coerceToImage\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \[lindex\ \[dict\ get\ \$gif\ frames\]\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ WARNING:\ This\ is\ not\ an\ Image\ object\ --\ it's\ a\ Gif\n\ \ \ \ \ \ \ \ \ \ \ \ #\ object\ and\ requires\ special\ handling\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$gif\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ \[fn\ gifLoader\]\ is\ an\ image\ loader\n\}\n\n\nWhen\ the\ collected\ results\ for\ \{/loader/\ is\ an\ image\ loader\}\ are\ /loaders/\ \{\n\ \ \ \ #\ Pass\ coerceToImage\ =\ 0\ if\ the\ caller\ is\ willing\ to\ handle\ a\ Gif\n\ \ \ \ #\ object,\ not\ just\ a\ normal\ Image.\n\ \ \ \ fn\ loadImage\ \{im\ \{coerceToImage\ 1\}\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ image\ loader\ is\ \[fn\ loadImage\]\n\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"image\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.01)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ return\ texColor\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\}\}\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ image\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\n\ \ \ \ set\ im\ \[dict\ get\ \$options\ image\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ \n\ \ \ \ if\ \{\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ width\]\ &&\ !\[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ \ \ \ \ set\ height\ \$(double(\[\$imageLib\ Image_height\ \$im\])\ /\ \[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ \}\ elseif\ \{!\[dict\ exists\ \$options\ width\]\ &&\ \[dict\ exists\ \$options\ height\]\}\ \{\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ \ \ \ \ set\ width\ \$(double(\[\$imageLib\ Image_width\ \$im\])\ /\ \[\$imageLib\ Image_height\ \$im\]\ *\ \$height)\n\ \ \ \ \}\n\n\ \ \ \ #\ TODO:\ implement\ anchor\ like\ in\ text\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"topleft\"\]\n\ \ \ \ if\ \{\$anchor\ eq\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ -\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \$(\$x0\ +\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$(\$x0\ -\ \$width/2.0)\ \$(\$y0\ +\ \$height/2.0)\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ eq\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ a\ \[list\ \$x0\ \$y0\]\n\ \ \ \ \ \ \ \ set\ b\ \[list\ \[+\ \$x0\ \$width\]\ \$y0\]\n\ \ \ \ \ \ \ \ set\ c\ \[list\ \[+\ \$x0\ \$width\]\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \ \ \ \ set\ d\ \[list\ \$x0\ \[+\ \$y0\ \$height\]\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ error\ \"Unsupported\ anchor:\ \$anchor\"\n\ \ \ \ \}\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\n\ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$gim\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$a\ \$b\ \$c\ \$d\]\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ image\ loader\ is\ /loadImage/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ displays\ image\ /impath/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ #\ HACK:\ because\ we\ match\ partially\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ fn\ loadImage\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ im\ \[loadImage\ \$impath\ 0\]\n\ \ \ \ \}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ \ \ \ \ Say\ \$p\ has\ error\ \$e\ with\ info\ \$opts\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\ \ \ \ if\ \{\[string\ match\ \"*gif\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ displays\ gif\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ width\ \[/\ \[dict\ getdef\ \$geom\ left\ \[dict\ get\ \$geom\ width\]\]\ 1.5\]\n\ \ \ \ set\ derivedHeight\ \$(double(\[\$imageLib\ Image_height\ \$im\])/\[\$imageLib\ Image_width\ \$im\]\ *\ \$width)\n\ \ \ \ set\ geomHeight\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ if\ \{\$derivedHeight\ >\ \$geomHeight\}\ \{\n\ \ \ \ \ \ \ \ set\ width\ \$(\$geomHeight\ /\ \$derivedHeight\ *\ \$width)\n\ \ \ \ \}\n\ \ \ \ Wish\ to\ draw\ an\ image\ onto\ \$p\ with\ \\\n\ \ \ \ \ \ \ \ image\ \$im\ \\\n\ \ \ \ \ \ \ \ position\ \[dict\ getdef\ \$options\ position\ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ anchor\ topleft\ width\ \[dict\ getdef\ \$options\ width\ \$width\]\n\n\}\n\nWhen\ /someone/\ wishes\ /p/\ displays\ image\ /im/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ scale\ 1.0\n\}\n
<unknown> claims builtin-programs/draw/apriltags.folk has program code Wish\ the\ GPU\ compiles\ pipe (
[ m58:0 (s91:0) ]
)<unknown> claims builtin-programs/draw/apriltags.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ \"apriltag\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\ vec4\ background\n\ \ \ \ \ uvec4\ tagBitsVec\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\n\ \ \ \ \ \ \ \ int\ x\ =\ int(uv.x\ *\ 10)\;\ int\ y\ =\ int(uv.y\ *\ 10)\;\n\ \ \ \ \ \ \ \ int\ bitIdx\ =\ y\ *\ 10\ +\ x\;\n\ \ \ \ \ \ \ \ uint\ bit\ =\ (tagBitsVec\[bitIdx\ /\ 32\]\ >>\ (bitIdx\ %\ 32))\ &\ 0x1\;\n\ \ \ \ \ \ \ \ return\ bit\ ==\ 1\ ?\ background\ :\ vec4(0,\ 0,\ 0,\ 1)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /writableTexture/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ an\ AprilTag\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ id\ \[dict\ get\ \$options\ id\]\n\ \ \ \ set\ corners\ \[dict\ get\ \$options\ corners\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ background\ \[dict\ getdef\ \$options\ background\ \[list\ 1\ 1\ 1\ 1\]\]\n\n\ \ \ \ set\ tagImage\ \[\$printLib\ tagImageForId\ \$id\]\n\ \ \ \ set\ tagBits\ \[list\]\n\ \ \ \ #\ 10x10\ AprilTag\ ->\ 100\ bits\n\ \ \ \ for\ \{set\ y\ 0\}\ \{\$y\ <\ 10\}\ \{incr\ y\}\ \{\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ 10\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ j\ \[expr\ \{\$y\ *\ \[\$imageLib\ Image_bytesPerRow\ \$tagImage\]\ +\ \$x\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ bit\ \$(\[\$imageLib\ Image_data\ \$tagImage\ \$j\]\ ==\ 255)\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ tagBits\ \$bit\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ ->\ 4\ 32-bit\ integers\n\ \ \ \ set\ tagBitsVec\ \[list\ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 0\ 31\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 32\ 63\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 64\ 95\]\]\ \"\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0b\[join\ \[lreverse\ \[lrange\ \$tagBits\ 96\ 127\]\]\ \"\"\]\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"apriltag\"\ onto\ canvas\ \$writableTexture\ with\ \\\n\ \ \ \ \ \ \ \ arguments\ \[list\ \$wiResolution\ \$surfaceToClip\ \$background\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagBitsVec\ \{*\}\$corners\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n
<unknown> claims builtin-programs/draw/fill.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ (
[ m60:0 (s95:0) ]
)<unknown> claims builtin-programs/draw/fill.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ \"fillTriangle\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](p0,\ p1,\ p2,\ p0,\ p0,\ p0)\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ return\ color\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ \{\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ triangle\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ quad\ onto\ /p/\ with\ /...options/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ layer\]\}\ \{\ set\ layer\ 0\ \}\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$color\]\ layer\ \$layer\n\ \ \ \ \}\n\}\nWhen\ /someone/\ wishes\ to\ draw\ a\ polygon\ with\ /...options/\ \{\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ set\ num_points\ \[llength\ \$points\]\n\ \ \ \ if\ \{\$num_points\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ error\ \"At\ least\ 3\ points\ are\ required\ to\ form\ a\ polygon.\"\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ triangle\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ elseif\ \{\$num_points\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ p0\ \[lindex\ \$points\ 0\]\ p1\ \[lindex\ \$points\ 1\]\ p2\ \[lindex\ \$points\ 2\]\ p3\ \[lindex\ \$points\ 3\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ \$color\ layer\ \$layer\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Get\ the\ first\ point\ in\ the\ list\ as\ the\ \"base\"\ point\ of\ the\ triangles\n\ \ \ \ \ \ \ \ set\ p0\ \[lindex\ \$points\ 0\]\n\n\ \ \ \ \ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \$num_points\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p1\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p2\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$color\]\ layer\ \$layer\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\}\n\nWhen\ /someone/\ wishes\ /page/\ is\ filled\ with\ /...options/\ &\\\n\ \ \ \ \ /page/\ has\ region\ /region/\ \{\n\ \ set\ points\ \[region\ vertices\ \$region\]\n\ \ Wish\ to\ draw\ a\ polygon\ with\ points\ \$points\ \{*\}\$options\n\}\n
<unknown> claims builtin-programs/draw/dashed-line.folk has program code Wish\ the\ GPU\ compiles\ pi (
[ m62:0 (s98:0) ]
)<unknown> claims builtin-programs/draw/dashed-line.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ \"dashed-line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\n\ \ \ \ \ float\ dashlength\ float\ dashoffset\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\n\ \ \ \ \ \ \ \ //\ How\ far\ are\ we\ along\ the\ line?\ (in\ pixels)\n\ \ \ \ \ \ \ \ float\ t\ =\ dot(surfaceXy.xy\ -\ from,\ to\ -\ from)\ /\ l\ +\ dashoffset\;\n\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0\ &&\ floor(mod(t\ /\ dashlength,\ 2.0))\ ==\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ dashed\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ dashlength\ \[dict\ getdef\ \$options\ dashlength\ 4\]\n\ \ \ \ set\ dashoffset\ \[dict\ getdef\ \$options\ dashoffset\ 0\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[expr\ \{\$i+1\}\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ \$width\ \$color\ \$dashlength\ \$dashoffset\]\n\ \ \ \ \}\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"dashed-line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n
<unknown> claims builtin-programs/draw/line.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ (
[ m64:0 (s101:0) ]
)<unknown> claims builtin-programs/draw/line.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ \"line\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ from\ vec2\ to\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ \ \ \ \ vec2\ dir\ =\ normalize(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ perp\ =\ vec2(-dir.y,\ dir.x)\ *\ thickness/2.0\;\n\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ from\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\n\ \ \ \ \ \ \ \ \ \ \ \ from\ +\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ -\ perp,\n\ \ \ \ \ \ \ \ \ \ \ \ to\ +\ perp\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ l\ =\ length(to\ -\ from)\;\n\ \ \ \ \ \ \ \ vec2\ d\ =\ (to\ -\ from)\ /\ l\;\n\ \ \ \ \ \ \ \ vec2\ q\ =\ (surfaceXy.xy\ -\ (from\ +\ to)*0.5)\;\n\ \ \ \ \ \ \ \ q\ =\ mat2(d.x,\ -d.y,\ d.y,\ d.x)\ *\ q\;\n\ \ \ \ \ \ \ \ q\ =\ abs(q)\ -\ vec2(l,\ thickness)*0.5\;\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(max(q,\ 0.0))\ +\ min(max(q.x,\ q.y),\ 0.0)\;\n\n\ \ \ \ \ \ \ \ return\ (dist\ <\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ line\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ set\ points\ \[dict\ get\ \$options\ points\]\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ set\ instances\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$points\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ from\ \[lindex\ \$points\ \$i\]\n\ \ \ \ \ \ \ \ set\ to\ \[lindex\ \$points\ \[+\ \$i\ 1\]\]\n\ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \$from\ \$to\ \$width\ \$color\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\}\n
<unknown> claims builtin-programs/draw/gif.folk has program code When\ the\ gif\ library\ is\ /gifLib (
[ m66:0 (s104:0) ]
)<unknown> claims builtin-programs/draw/gif.folk has program code When\ the\ gif\ library\ is\ /gifLib/\ \{\n\ \ When\ /someone/\ wishes\ /p/\ displays\ gif\ /gif/\ with\ /...options/\ &\\\n\ \ \ \ \ \ \ /p/\ has\ resolved\ geometry\ /geom/\ \{\n\n\ \ \ \ \ \ set\ frames\ \[dict\ get\ \$gif\ frames\]\n\ \ \ \ \ \ set\ delays\ \[dict\ get\ \$gif\ delays\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ totalDuration\ 0\n\ \ \ \ \ \ set\ cumulativeDelays\ \[list\]\n\ \ \ \ \ \ foreach\ d\ \$delays\ \{\n\ \ \ \ \ \ \ \ \ \ if\ \{\$d\ <=\ 10\}\ \{\ set\ d\ 100\ \}\n\ \ \ \ \ \ \ \ \ \ incr\ totalDuration\ \$d\n\ \ \ \ \ \ \ \ \ \ lappend\ cumulativeDelays\ \$totalDuration\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ if\ \{\[llength\ \$frames\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \[lindex\ \$frames\ 0\]\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ set\ ms\ \[expr\ \{int(\$t\ *\ 1000)\ %\ \$totalDuration\}\]\n\ \ \ \ \ \ \ \ \ \ set\ frameIdx\ 0\n\ \ \ \ \ \ \ \ \ \ foreach\ cd\ \$cumulativeDelays\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ms\ <\ \$cd\}\ \{\ break\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ frameIdx\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ if\ \{\$frameIdx\ >=\ \[llength\ \$frames\]\}\ \{\ set\ frameIdx\ 0\ \}\n\ \ \ \ \ \ \ \ \ \ set\ im\ \[lindex\ \$frames\ \$frameIdx\]\n\ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ Wish\ \$p\ displays\ image\ \$im\ with\ \{*\}\$options\n\ \ \ \ \ \ \}\n\ \ \}\n\}\n
<unknown> claims builtin-programs/draw/circle.folk has program code Wish\ the\ GPU\ compiles\ pipelin (
[ m68:0 (s106:0) ]
)<unknown> claims builtin-programs/draw/circle.folk has program code Wish\ the\ GPU\ compiles\ pipeline\ \"circle\"\ \{\n\ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ vec2\ center\ float\ radius\ float\ thickness\ vec4\ color\ int\ filled\}\ \{\n\ \ \ \ \ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ \ \ \ center\ +\ r,\n\ \ \ \ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r)\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ float\ dist\ =\ length(surfaceXy.xy\ -\ center)\ -\ radius\;\n\ \ \ \ \ \ \ \ if\ (filled\ ==\ 1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ ?\ color\ :\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ /p/\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ a\ circle\ onto\ /p/\ with\ /...options/\ \{\n\n\ \ \ \ set\ center\ \[dict\ getdef\ \$options\ center\ \"\"\]\n\ \ \ \ if\ \{\$center\ eq\ \"\"\}\ \{\ set\ center\ \[list\ \[dict\ get\ \$options\ x\]\ \[dict\ get\ \$options\ y\]\]\ \}\n\ \ \ \ set\ radius\ \[dict\ get\ \$options\ radius\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[dict\ get\ \$options\ color\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ filled\ \[dict\ getdef\ \$options\ filled\ false\]\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"circle\"\ onto\ canvas\ \$id\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$center\ \$radius\ \$thickness\ \$color\ \[expr\ \{\$filled\ eq\ false\ ?\ 0\ :\ 1\}\]\]\n\}\n
<unknown> claims builtin-programs/draw/text.folk has program code When\ the\ image\ library\ is\ /ima (
[ m71:0 (s114:0) ]
)<unknown> claims builtin-programs/draw/text.folk has program code When\ the\ image\ library\ is\ /imageLib/\ \{\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ include\ <math.h>\n\n\$cc\ struct\ GlyphInfo\ \{\n\ \ \ \ float\ advance\;\n\ \ \ \ float\ planeBounds\[4\]\;\n\ \ \ \ float\ atlasBounds\[4\]\;\n\}\n\$cc\ struct\ Font\ \{\n\ \ \ \ Image\ atlasImage\;\n\ \ \ \ int\ gpuAtlasImage\;\n\ \ \ \ //\ TODO:\ This\ only\ handles\ ASCII,\ obviously.\n\ \ \ \ GlyphInfo\ glyphInfos\[128\]\;\n\}\n\n\$cc\ struct\ vec2f\ \{\ float\ x\;\ float\ y\;\ \}\n\$cc\ proc\ vec2f_add\ \{vec2f\ a\ vec2f\ b\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\ a.x\ +\ b.x,\ a.y\ +\ b.y\ \}\;\n\}\n\$cc\ proc\ vec2f_rotate\ \{vec2f\ a\ float\ radians\}\ vec2f\ \{\n\ \ \ \ return\ (vec2f)\ \{\n\ \ \ \ \ \ \ \ a.x*cosf(radians)\ +\ a.y*sinf(radians),\n\ \ \ \ \ \ \ \ -a.x*sinf(radians)\ +\ a.y*cosf(radians)\n\ \ \ \ \}\;\n\}\n\$cc\ proc\ vec2f_toObj\ \{vec2f\ a\}\ Jim_Obj*\ \{\n\ \ \ \ Jim_Obj\ *v\[\]\ =\ \{\ Jim_NewDoubleObj(interp,\ a.x),\ Jim_NewDoubleObj(interp,\ a.y)\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ v,\ 2)\;\n\}\n\$cc\ proc\ charOrFallback\ \{Font*\ font\ int\ ch\}\ int\ \{\n\ \ \ \ if\ (ch\ <\ '\ '\ ||\ ch\ >=\ sizeof(font->glyphInfos)/sizeof(font->glyphInfos\[0\]))\ \{\n\ \ \ \ \ \ \ \ return\ '?'\;\n\ \ \ \ \}\n\ \ \ \ return\ ch\;\n\}\n\$cc\ proc\ textExtent\ \{Font*\ font\ char*\ text\ float\ scale\}\ vec2f\ \{\n\ \ \ \ float\ em\ =\ scale\;\n\ \ \ \ float\ x\ =\ 0\;\ float\ y\ =\ 0\;\n\ \ \ \ float\ width\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ y\ +\ em\;\ x\ =\ 0\;\ continue\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\n\ \ \ \ \ \ \ \ x\ =\ x\ +\ font->glyphInfos\[ch\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ if\ (x\ >\ width)\ \{\ width\ =\ x\;\ \}\n\ \ \ \ \}\n\ \ \ \ return\ (vec2f)\ \{\ width,\ y\ \}\;\n\}\n\$cc\ proc\ textShape\ \{Jim_Obj*\ viewport\ Jim_Obj*\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Font*\ font\ char*\ text\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ x0\ float\ y0\ float\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ blockAnchorX\ float\ blockAnchorY\ float\ lineAnchorX\ float\ lineAnchorY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ float\ radians\ Jim_Obj*\ color\}\ Jim_Obj*\ \{\n\ \ \ \ vec2f\ extent\ =\ textExtent(font,\ text,\ scale)\;\n\ \ \ \ float\ em\ =\ scale\;\n\n\ \ \ \ //\ The\ anchor\ origin\ goes\ from\ top-left\ (0.0)\ to\ bottom-right\ (1.0).\n\ \ \ \ float\ blockOffsetX\ =\ -(blockAnchorX\ *\ extent.x)\;\n\ \ \ \ //\ `lineAnchorY\ -\ 1`\ because\ the\ font\ is\ relative\ to\ the\ bottom,\ while\ we're\ relative\ to\ the\ top.\n\ \ \ \ float\ blockOffsetY\ =\ -(blockAnchorY\ *\ extent.y\ +\ (lineAnchorY\ -\ 1)\ *\ em)\;\n\ \ \ \ //\ Offset\ is\ rotated\ before\ adding\ (x0,\ y0),\ so\ that\ text\ is\ relative\n\ \ \ \ //\ to\ (x0,\ y0).\n\ \ \ \ vec2f\ rotatedBlockOffset\ =\ vec2f_rotate((vec2f)\ \{blockOffsetX,\ blockOffsetY\},\ radians)\;\n\ \ \ \ vec2f\ blockStart\ =\ (vec2f)\ \{\ x0\ +\ rotatedBlockOffset.x,\ y0\ +\ rotatedBlockOffset.y\ \}\;\n\n\ \ \ \ //\ Need\ to\ get\ the\ initial\ line\ width\ so\ the\ line\ is\ relative\ to\ lineAnchorX.\ We\n\ \ \ \ //\ later\ recalculate\ this\ whenever\ we\ hit\ '\\n',\ but\ obviously\ that\ doesn't\ work\ at\n\ \ \ \ //\ the\ start.\n\ \ \ \ float\ lineWidth\ =\ 0.0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ '\\n'\ &&\ text\[i\]\ !=\ '\\0'\;\ i++)\ \{\n\ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[i\])\].advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Get\ the\ string\ representations\ of\ the\ shared\ per-label\ args\ once,\n\ \ \ \ //\ before\ the\ loop,\ so\ we\ don't\ call\ Jim_GetString\ (which\ may\ trigger\n\ \ \ \ //\ UpdateStringOfDouble\ for\ every\ float)\ N\ times\ per\ glyph.\n\ \ \ \ const\ char*\ sc_str\ \ \ \ =\ Jim_GetString(surfaceToClip,\ NULL)\;\n\ \ \ \ const\ char*\ color_str\ =\ Jim_GetString(color,\ NULL)\;\n\ \ \ \ const\ char*\ vp_str\ \ \ \ =\ Jim_GetString(viewport,\ NULL)\;\n\ \ \ \ float\ atlas_w\ =\ (float)font->atlasImage.width\;\n\ \ \ \ float\ atlas_h\ =\ (float)font->atlasImage.height\;\n\n\ \ \ \ //\ Build\ the\ instances\ list\ as\ a\ pre-formatted\ Tcl\ list\ string.\n\ \ \ \ //\ Each\ element\ is\ a\ brace-enclosed\ instance:\ \{\{sc\}\ \{atlas\}\ \{color\}\ \{vp\}\ \{a\}\ \{b\}\ \{c\}\ \{d\}\ n\}\n\ \ \ \ //\ This\ avoids\ Jim\ ever\ calling\ UpdateStringOfList\ /\ ListElementQuotingType\ on\ instances.\n\ \ \ \ int\ textLen\ =\ strlen(text)\;\n\ \ \ \ int\ bufSize\ =\ (textLen\ +\ 1)\ *\ 320\;\n\ \ \ \ char*\ buf\ =\ (char*)malloc(bufSize)\;\n\ \ \ \ int\ pos\ =\ 0\;\n\ \ \ \ int\ needSpace\ =\ 0\;\n\n\ \ \ \ //\ Relative\ character\ position\ (relative\ to\ (0,\ 0),\ not\ rotated).\n\ \ \ \ float\ relCharX\ =\ 0\;\n\ \ \ \ float\ relCharY\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ text\[i\]\ !=\ 0\;\ i++)\ \{\n\ \ \ \ \ \ \ \ int\ ch\ =\ text\[i\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ ==\ '\\n')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ relCharX\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ relCharY\ +=\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ =\ 0.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ i\ +\ 1\;\ text\[j\]\ !=\ '\\n'\ &&\ text\[j\]\ !=\ '\\0'\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineWidth\ +=\ font->glyphInfos\[charOrFallback(font,\ text\[j\])\].advance\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ ch\ =\ charOrFallback(font,\ ch)\;\n\ \ \ \ \ \ \ \ GlyphInfo*\ glyphInfo\ =\ &font->glyphInfos\[ch\]\;\n\ \ \ \ \ \ \ \ if\ (ch\ !=\ '\ ')\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Calculate\ the\ absolute\ glyph\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ float\ lineOffsetX\ =\ -(lineAnchorX\ *\ lineWidth)\ -\ blockOffsetX\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ `lineOffsetY`\ doesn't\ exist,\ since\ it's\ already\ included\ in\ the\ `blockOffsetY`\ calculation.\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ rotatedLineOffset\ =\ vec2f_rotate((vec2f)\ \{\ lineOffsetX,\ 0\ \},\ radians)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ combinedOffset\ =\ vec2f_add(blockStart,\ rotatedLineOffset)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ charPos\ =\ vec2f_add(combinedOffset,\ vec2f_rotate((vec2f)\ \{\ relCharX,\ relCharY\ \},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ float\ left\ =\ glyphInfo->planeBounds\[0\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ bottom\ =\ glyphInfo->planeBounds\[1\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ right\ =\ glyphInfo->planeBounds\[2\]\ *\ em\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ top\ =\ glyphInfo->planeBounds\[3\]\ *\ em\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topLeft\ \ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ topRight\ \ \ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -top\},\ \ \ \ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomRight\ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{right,\ -bottom\},\ radians))\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2f\ bottomLeft\ \ =\ vec2f_add(charPos,\ vec2f_rotate((vec2f)\ \{left,\ \ -bottom\},\ radians))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (needSpace)\ buf\[pos++\]\ =\ '\ '\;\n\ \ \ \ \ \ \ \ \ \ \ \ needSpace\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pos\ +=\ snprintf(buf\ +\ pos,\ bufSize\ -\ pos,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\{\{%s\}\ \{%g\ %g\ %g\ %g\}\ \{%s\}\ \{%s\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ \{%g\ %g\}\ %d\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sc_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[0\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[1\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[2\]\ /\ atlas_w,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glyphInfo->atlasBounds\[3\]\ /\ atlas_h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vp_str,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topLeft.x,\ \ \ \ \ topLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ topRight.x,\ \ \ \ topRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomRight.x,\ bottomRight.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottomLeft.x,\ \ bottomLeft.y,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font->gpuAtlasImage)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Advance\ to\ next\ character\ position.\n\ \ \ \ \ \ \ \ relCharX\ +=\ glyphInfo->advance\ *\ em\;\n\ \ \ \ \}\n\n\ \ \ \ Jim_Obj*\ result\ =\ Jim_NewStringObj(interp,\ buf,\ pos)\;\n\ \ \ \ free(buf)\;\n\ \ \ \ return\ result\;\n\}\n\$cc\ proc\ fontNew\ \{Image\ atlasImage\ int\ gpuAtlasImage\ \{GlyphInfo\[128\]\}\ glyphInfos\}\ Font*\ \{\n\ \ \ \ Font*\ font\ =\ (Font*)\ malloc(sizeof(Font))\;\n\ \ \ \ font->atlasImage\ =\ atlasImage\;\n\ \ \ \ font->gpuAtlasImage\ =\ gpuAtlasImage\;\n\ \ \ \ memcpy(font->glyphInfos,\ glyphInfos,\ sizeof(font->glyphInfos))\;\n\ \ \ \ return\ font\;\n\}\n\$cc\ proc\ fontFree\ \{Font*\ font\}\ void\ \{\n\ \ \ \ free(font)\;\n\}\nset\ fontLib\ \[\$cc\ compile\]\n\nWhen\ the\ image\ loader\ is\ /loadImage/\ \{\n\ \ \ \ fn\ loadImage\n\ \ \ \ fn\ loadFont\ \{name\}\ \{\n\ \ \ \ \ \ \ \ set\ csvFd\ \[open\ \"vendor/fonts/\$name.csv\"\ r\]\;\ set\ csv\ \[read\ \$csvFd\]\;\ close\ \$csvFd\n\ \ \ \ \ \ \ \ set\ fields\ \[list\ \]\n\ \ \ \ \ \ \ \ #\ HACK:\ Create\ list\ of\ null\ glyphs\ to\ initialize.\n\ \ \ \ \ \ \ \ set\ glyphInfos\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 128\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ glyphInfos\ \{\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$csv\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ values\ \[lassign\ \[split\ \$line\ ,\]\ glyphIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[string\ is\ integer\ -strict\ \$glyphIdx\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$values\ advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeLeft\ planeBottom\ planeRight\ planeTop\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasLeft\ atlasBottom\ atlasRight\ atlasTop\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$glyphIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ advance\ \$advance\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeBounds\ \[list\ \$planeLeft\ \$planeBottom\ \$planeRight\ \$planeTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ atlasBounds\ \[list\ \$atlasLeft\ \$atlasBottom\ \$atlasRight\ \$atlasTop\]\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ defaultGlyphInfo\ \[lindex\ \$glyphInfos\ 63\]\ \;#\ '?'\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$glyphInfos\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$glyphInfos\ \$i\]\ eq\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ glyphInfos\ \$i\ \$defaultGlyphInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ im\ \[\{*\}\$loadImage\ \"\[pwd\]/vendor/fonts/\$name.png\"\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ loads\ image\ \$im\ as\ texture\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ /gim/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"text:\ Loaded\ \$name\ as\ GPU\ texture\ \$gim\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ font\ \[\$fontLib\ fontNew\ \$im\ \$gim\ \$glyphInfos\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ font\ \$name\ with\ data\ \$font\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$fontLib\ fontFree\ \$font\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ foreach\ fontPath\ \[list\ \{*\}\[glob\ vendor/fonts/*.png\]\]\ \{\n\ \ \ \ \ \ \ \ set\ fontName\ \"\"\n\ \ \ \ \ \ \ \ regexp\ \{vendor/fonts/(.*).png\}\ \$fontPath\ ->\ fontName\n\ \ \ \ \ \ \ \ if\ \{!(\$fontName\ eq\ \"\")\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ loadFont\ \$fontName\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWish\ the\ GPU\ compiles\ function\ \"glyphMsd\"\ \{\n\ \ \ \ \{sampler2D\ atlas\ vec4\ atlasGlyphBounds\ vec2\ glyphUv\}\ vec4\ \{\n\ \ \ \ \ \ \ \ vec2\ atlasUv\ =\ mix(atlasGlyphBounds.xw,\ atlasGlyphBounds.zy,\ glyphUv)\;\n\ \ \ \ \ \ \ \ return\ texture(atlas,\ vec2(atlasUv.x,\ 1.0-atlasUv.y))\;\n\ \ \ \ \}\n\}\nWish\ the\ GPU\ compiles\ function\ \"median\"\ \{\n\ \ \ \ \{float\ r\ float\ g\ float\ b\}\ float\ \{\n\ \ \ \ \ \ \ \ return\ max(min(r,\ g),\ min(max(r,\ g),\ b))\;\n\ \ \ \ \}\n\}\n\n#\ HACK:\ (?)\ the\ push\ constant\ args\ are\ ordered\ to\ minimize\ padding\ so\n#\ that\ it\ fits\ into\ 128\ bytes.\nWish\ the\ GPU\ compiles\ pipeline\ \"glyph\"\ \{\n\ \ \ \ \{mat3\ surfaceToClip\n\ \ \ \ \ vec4\ atlasGlyphBounds\n\ \ \ \ \ vec4\ color\n\ \ \ \ \ vec2\ viewport\n\ \ \ \ \ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\n\ \ \ \ \ sampler2D\ atlas\n\ \ \ \ \ fn\ rotate\}\ \{\n\n\ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\}\ \{fn\ rotate\ fn\ invBilinear\ fn\ glyphMsd\ fn\ median\}\ \{\n\ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ vec2\ glyphUv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ if(\ max(\ abs(glyphUv.x-0.5),\ abs(glyphUv.y-0.5))>=0.5\ )\ \{\n\ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\n\ \ \ \ vec3\ msd\ =\ glyphMsd(atlas,\ atlasGlyphBounds,\ glyphUv).rgb\;\n\ \ \ \ //\ https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817\n\ \ \ \ float\ sd\ =\ median(msd.r,\ msd.g,\ msd.b)\;\n\ \ \ \ float\ uBuffer\ =\ 0.2\;\n\ \ \ \ float\ uGamma\ =\ 0.2\;\n\ \ \ \ float\ opacity\ =\ smoothstep(uBuffer\ -\ uGamma,\ uBuffer\ +\ uGamma,\ sd)\;\n\n\ \ \ \ return\ (opacity\ <\ 0.01)\ ?\ vec4(0.0)\ :\ vec4(color.rgb,\ opacity\ *\ color.a)\;\n\}\}\n\nWhen\ the\ color\ map\ is\ /colorMap/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ text\ onto\ /p/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ position\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$options\ position\]\ x0\ y0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ x0\ \[dict\ get\ \$options\ x\]\n\ \ \ \ \ \ \ \ set\ y0\ \[dict\ get\ \$options\ y\]\n\ \ \ \ \}\n\ \ \ \ set\ scale\ \[dict\ getdef\ \$options\ scale\ 0.01\]\ \;#\ 1cm\ default\ scale\n\ \ \ \ set\ font\ \[dict\ getdef\ \$options\ font\ \"PTSans-Regular\"\]\n\ \ \ \ set\ text\ \[dict\ get\ \$options\ text\]\n\ \ \ \ set\ anchor\ \[dict\ getdef\ \$options\ anchor\ \"center\"\]\n\ \ \ \ set\ radians\ \[dict\ getdef\ \$options\ radians\ 0\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$options\ color\ white\]\n\ \ \ \ set\ color\ \[dict\ getdef\ \$colorMap\ \$color\ \$color\]\n\ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ if\ \{\$anchor\ ==\ \"topleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0\ 0\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"top\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0\ 0.5\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"topright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0\ 1\ 0\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"left\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 0.5\ 0\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"center\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 0.5\ 0.5\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"right\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1.0\ 0.5\ 1\ 0.5\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomleft\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0\ 1\ 0\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottom\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 0.5\ 1\ 0.5\ 1\]\n\ \ \ \ \}\ elseif\ \{\$anchor\ ==\ \"bottomright\"\}\ \{\n\ \ \ \ \ \ \ \ set\ anchor\ \[list\ 1\ 1\ 1\ 1\]\n\ \ \ \ \}\n\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ \ \ \ \ the\ GPU\ has\ font\ \$font\ with\ data\ /fontData/\ \{\n\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ set\ instances\ \[\$fontLib\ textShape\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fontData\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$text\ \$x0\ \$y0\ \$scale\ \{*\}\$anchor\ \$radians\ \$color\]\n\n\ \ \ \ \ \ \ \ #\ We\ need\ to\ batch\ into\ one\ wish\ so\ we\ don't\ deal\ with\ n^2\n\ \ \ \ \ \ \ \ #\ checks\ for\ existing\ statements\ for\ n\ glyphs.\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"glyph\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\ layer\ \$layer\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/draw/color-map.folk has program code {proc hexcolor color {
set (
[ m72:0 (s111:0) ]
)<unknown> claims builtin-programs/draw/color-map.folk has program code {proc hexcolor color {
set color 0x$color
set b [expr {$color & 0xFF}]
set g [expr {($color >> 8) & 0xFF}]
set r [expr {($color >> 16) & 0xFF}]
return [list [/ $r 255.0] [/ $g 255.0] [/ $b 255.0] 1.0]
}
set colors {
aliceblue F0F8FF
antiquewhite FAEBD7
aqua 00FFFF
aquamarine 7FFFD4
azure F0FFFF
beige F5F5DC
bisque FFE4C4
black 000000
blanchedalmond FFEBCD
blue 0000FF
blueviolet 8A2BE2
brown A52A2A
burlywood DEB887
cadetblue 5F9EA0
chartreuse 7FFF00
chocolate D2691E
coral FF7F50
cornflowerblue 6495ED
cornsilk FFF8DC
crimson DC143C
cyan 00FFFF
darkblue 00008B
darkcyan 008B8B
darkgoldenrod B8860B
darkgray A9A9A9
darkgreen 006400
darkgrey A9A9A9
darkkhaki BDB76B
darkmagenta 8B008B
darkolivegreen 556B2F
darkorange FF8C00
darkorchid 9932CC
darkred 8B0000
darksalmon E9967A
darkseagreen 8FBC8F
darkslateblue 483D8B
darkslategray 2F4F4F
darkslategrey 2F4F4F
darkturquoise 00CED1
darkviolet 9400D3
deeppink FF1493
deepskyblue 00BFFF
dimgray 696969
dimgrey 696969
dodgerblue 1E90FF
firebrick B22222
floralwhite FFFAF0
forestgreen 228B22
fuchsia FF00FF
gainsboro DCDCDC
ghostwhite F8F8FF
gold FFD700
goldenrod DAA520
gray 808080
green 008000
greenyellow ADFF2F
grey 808080
honeydew F0FFF0
hotpink FF69B4
indianred CD5C5C
indigo 4B0082
ivory FFFFF0
khaki F0E68C
lavender E6E6FA
lavenderblush FFF0F5
lawngreen 7CFC00
lemonchiffon FFFACD
lightblue ADD8E6
lightcoral F08080
lightcyan E0FFFF
lightgoldenrodyellow FAFAD2
lightgray D3D3D3
lightgreen 90EE90
lightgrey D3D3D3
lightpink FFB6C1
lightsalmon FFA07A
lightseagreen 20B2AA
lightskyblue 87CEFA
lightslategray 778899
lightslategrey 778899
lightsteelblue B0C4DE
lightyellow FFFFE0
lime 00FF00
limegreen 32CD32
linen FAF0E6
magenta FF00FF
maroon 800000
mediumaquamarine 66CDAA
mediumblue 0000CD
mediumorchid BA55D3
mediumpurple 9370DB
mediumseagreen 3CB371
mediumslateblue 7B68EE
mediumspringgreen 00FA9A
mediumturquoise 48D1CC
mediumvioletred C71585
midnightblue 191970
mintcream F5FFFA
mistyrose FFE4E1
moccasin FFE4B5
navajowhite FFDEAD
navy 000080
oldlace FDF5E6
olive 808000
olivedrab 6B8E23
orange FFA500
orangered FF4500
orchid DA70D6
palegoldenrod EEE8AA
palegreen 98FB98
paleturquoise AFEEEE
palevioletred DB7093
papayawhip FFEFD5
peachpuff FFDAB9
peru CD853F
pink FFC0CB
plum DDA0DD
powderblue B0E0E6
purple 800080
rebeccapurple 663399
red FF0000
rosybrown BC8F8F
royalblue 4169E1
saddlebrown 8B4513
salmon FA8072
sandybrown F4A460
seagreen 2E8B57
seashell FFF5EE
sienna A0522D
silver C0C0C0
skyblue 87CEEB
slateblue 6A5ACD
slategray 708090
slategrey 708090
snow FFFAFA
springgreen 00FF7F
steelblue 4682B4
tan D2B48C
teal 008080
thistle D8BFD8
tomato FF6347
turquoise 40E0D0
violet EE82EE
wheat F5DEB3
white FFFFFF
whitesmoke F5F5F5
yellow FFFF00
yellowgreen 9ACD32
}
set colorMap [dict create]
foreach {color hex} $colors {
dict set colorMap $color [hexcolor $hex]
}
Claim the color map is $colorMap
}
<unknown> claims builtin-programs/image/gif-lib.folk has program code {When the image library is /ima (
[ m73:0 (s113:0) ]
)<unknown> claims builtin-programs/image/gif-lib.folk has program code {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc cflags -I./vendor/gifdec
$cc endcflags ./vendor/gifdec/gifdec.c -fPIC
$cc include "gifdec.h"
$cc include <stdlib.h>
$cc proc loadGif {char* filename} Jim_Obj* {
gd_GIF *gif = gd_open_gif(filename);
if (!gif) {
FOLK_ERROR("loadGif: Failed to open %s", filename);
}
Jim_Obj *framesList = Jim_NewListObj(interp, NULL, 0);
Jim_Obj *delaysList = Jim_NewListObj(interp, NULL, 0);
while (gd_get_frame(gif)) {
Image im;
im.width = gif->width;
im.height = gif->height;
im.components = 3;
im.bytesPerRow = im.width * 3;
im.data = malloc(im.bytesPerRow * im.height);
im.uniq = 0;
gd_render_frame(gif, im.data);
// Box the Image struct into a Tcl object
Jim_Obj *imObj;
$[$cc ret Image imObj im]
Jim_ListAppendElement(interp, framesList, imObj);
// gifdec delay is in 1/100s of a second. Convert to milliseconds.
Jim_ListAppendElement(interp, delaysList, Jim_NewIntObj(interp, gif->gce.delay * 10));
}
uint16_t w = gif->width;
uint16_t h = gif->height;
gd_close_gif(gif);
Jim_Obj *result = Jim_NewDictObj(interp, NULL, 0);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "frames", -1), framesList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "delays", -1), delaysList);
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "width", -1), Jim_NewIntObj(interp, w));
Jim_DictAddElement(interp, result, Jim_NewStringObj(interp, "height", -1), Jim_NewIntObj(interp, h));
return result;
}
set gifLib [$cc compile]
Claim the gif library is $gifLib
}
}
<unknown> claims builtin-programs/image/jpeg-lib.folk has program code {When the image library is /im (
[ m76:0 (s119:0) ]
)<unknown> claims builtin-programs/image/jpeg-lib.folk has program code {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lturbojpeg
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Jpeg {
uint8_t* start;
size_t length;
}
$cc code {
#undef EXTERN
#include <turbojpeg.h>
#include <stdint.h>
void
jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality)
{
tjhandle handle = tjInitCompress();
if (handle == NULL) {
FOLK_ERROR("jpeg: Failed to initialize compressor");
}
unsigned char* jpegBuf = NULL;
unsigned long jpegSize = 0;
int pixelFormat;
uint8_t* srcData;
int pitch;
if (components == 1) {
// Convert grayscale to RGB to maintain original behavior
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
uint8_t gray = data[i * bytesPerRow + j];
srcData[(i * width + j) * 3 + 0] = gray;
srcData[(i * width + j) * 3 + 1] = gray;
srcData[(i * width + j) * 3 + 2] = gray;
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else if (components == 3) {
if (bytesPerRow == width * 3) {
// Data is contiguous, use directly
srcData = data;
} else {
// Need to copy to contiguous buffer
srcData = malloc(width * height * 3);
for (size_t i = 0; i < height; i++) {
memcpy(srcData + i * width * 3, data + i * bytesPerRow, width * 3);
}
}
pixelFormat = TJPF_RGB;
pitch = width * 3;
} else {
tjDestroy(handle);
FOLK_ERROR("jpeg: Unsupported number of components: %d", components);
}
int ret = tjCompress2(handle, srcData, width, pitch, height, pixelFormat,
&jpegBuf, &jpegSize, TJSAMP_444, quality, TJFLAG_FASTDCT);
if (components == 1 || (components == 3 && bytesPerRow != width * 3)) {
free(srcData);
}
if (ret != 0) {
tjDestroy(handle);
FOLK_ERROR("jpeg: Compression failed: %s", tjGetErrorStr());
}
fwrite(jpegBuf, 1, jpegSize, dest);
tjFree(jpegBuf);
tjDestroy(handle);
}
}
$cc proc jpegDimensions {Jpeg jpeg} Jim_Obj* {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDimensions: Failed to initialize decompressor");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegDimensions: Failed to read header: %s", tjGetErrorStr());
}
tjDestroy(handle);
Jim_Obj* elems[2];
elems[0] = Jim_NewIntObj(interp, width);
elems[1] = Jim_NewIntObj(interp, height);
return Jim_NewListObj(interp, elems, 2);
}
$cc proc jpegData {Jpeg jpeg} Jim_Obj* {
return Jim_NewStringObj(interp, (char *)jpeg.start, jpeg.length);
}
$cc proc saveAsJpeg {Image im char* filename} void {
FILE* out = fopen(filename, "w");
FOLK_ENSURE(out != NULL);
jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100);
fclose(out);
}
$cc proc loadJpeg {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s", filename);
}
// Read entire file into buffer
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char* jpegBuf = malloc(fileSize);
if (fread(jpegBuf, 1, fileSize, file) != fileSize) {
fclose(file);
FOLK_ERROR("Error reading file: %s", filename);
}
fclose(file);
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
free(jpegBuf);
FOLK_ERROR("loadJpeg: Failed to initialize decompressor");
}
int width, height, jpegSubsamp, jpegColorspace;
if (tjDecompressHeader3(handle, jpegBuf, fileSize, &width, &height,
&jpegSubsamp, &jpegColorspace) != 0) {
free(jpegBuf);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Failed to read header: %s", tjGetErrorStr());
}
// Determine output format based on colorspace
int pixelFormat = (jpegColorspace == TJCS_GRAY) ? TJPF_GRAY : TJPF_RGB;
int components = (jpegColorspace == TJCS_GRAY) ? 1 : 3;
Image ret;
ret.width = width;
ret.height = height;
ret.components = components;
ret.bytesPerRow = ret.width * ret.components;
ret.data = malloc(ret.bytesPerRow * ret.height);
if (tjDecompress2(handle, jpegBuf, fileSize, ret.data, width, 0, height,
pixelFormat, 0) != 0) {
free(jpegBuf);
free(ret.data);
tjDestroy(handle);
FOLK_ERROR("loadJpeg: Decompression failed: %s", tjGetErrorStr());
}
free(jpegBuf);
tjDestroy(handle);
return ret;
}
$cc proc jpegSubimage {Jpeg jpeg double x double y double subwidth double subheight} Jpeg {
tjhandle handle = tjInitTransform();
if (handle == NULL) {
FOLK_ERROR("jpegSubimage: Failed to init transform");
}
int width, height, subsamp, colorspace;
if (tjDecompressHeader3(handle, jpeg.start, jpeg.length, &width, &height, &subsamp, &colorspace) != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Failed to read header: %s", tjGetErrorStr());
}
int mcuWidth, mcuHeight;
switch (subsamp) {
case TJSAMP_GRAY: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_444: mcuWidth = 8; mcuHeight = 8; break;
case TJSAMP_422: mcuWidth = 16; mcuHeight = 8; break;
case TJSAMP_420: mcuWidth = 16; mcuHeight = 16; break;
case TJSAMP_440: mcuWidth = 8; mcuHeight = 16; break;
case TJSAMP_411: mcuWidth = 32; mcuHeight = 8; break;
default:
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Unsupported subsampling: %d", subsamp);
}
if ((int)x % mcuWidth != 0 || (int)y % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop start not aligned to MCU: %d %d", (int)x, (int)y);
}
int startX = ((int)x / mcuWidth) * mcuWidth;
int startY = ((int)y / mcuHeight) * mcuHeight;
if ((int)subwidth % mcuWidth != 0 || (int)subheight % mcuHeight != 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Crop size not aligned to MCU: %d %d", (int)subwidth, (int)subheight);
}
int endX = startX + (int)subwidth;
int endY = startY + (int)subheight;
if (endX > width) endX = width;
if (endY > height) endY = height;
int cropWidth = ((endX - startX) / mcuWidth) * mcuWidth;
int cropHeight = ((endY - startY) / mcuHeight) * mcuHeight;
if (cropWidth <= 0 || cropHeight <= 0) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: Invalid crop size after MCU alignment");
}
tjregion region = { .x = startX, .y = startY, .w = cropWidth, .h = cropHeight };
tjtransform transform;
memset(&transform, 0, sizeof(transform));
transform.r = region;
transform.op = TJXOP_NONE;
transform.options = TJXOPT_CROP;
// Pre-allocate buffer with worst-case size
unsigned long outSize = tjBufSize(cropWidth, cropHeight, TJSAMP_444);
unsigned char* outBuf = malloc(outSize);
if (!outBuf) {
tjDestroy(handle);
FOLK_ERROR("jpegSubimage: malloc failed");
}
if (tjTransform(handle, jpeg.start, jpeg.length, 1, &outBuf, &outSize, &transform, TJFLAG_NOREALLOC) != 0) {
tjDestroy(handle);
free(outBuf);
FOLK_ERROR("jpegSubimage: Transform failed: %s", tjGetErrorStr());
}
tjDestroy(handle);
return (Jpeg) {
.start = outBuf,
.length = outSize
};
}
$cc proc jpegDecompressGray {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("cameraDecompressGray: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 1, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_GRAY, TJFLAG_FASTDCT);
if (ret != 0) {
// Check if this is just a warning (e.g., "extraneous bytes before marker")
// or a fatal error. Warnings are common with webcam MJPEG streams.
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("cameraDecompressGray: Decompression failed: %s", tjGetErrorStr());
}
// For warnings, continue with the (possibly partially corrupted) image
// fprintf(stderr, "cameraDecompressGray: Warning: %s", tjGetErrorStr());
}
tjDestroy(handle);
return dest;
}
$cc proc jpegDecompressRGB {Jpeg jpeg int width int height int uniq} Image {
tjhandle handle = tjInitDecompress();
if (handle == NULL) {
FOLK_ERROR("jpegDecompressRGB: Failed to initialize decompressor");
}
Image dest = imageNew(width, height, 3, uniq);
int ret = tjDecompress2(handle, jpeg.start, jpeg.length,
dest.data, width, 0, height, TJPF_RGB, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
if (ret != 0) {
int errCode = tjGetErrorCode(handle);
if (errCode == TJERR_FATAL) {
tjDestroy(handle);
FOLK_ERROR("jpegDecompressRGB: Decompression failed: %s", tjGetErrorStr());
}
}
tjDestroy(handle);
return dest;
}
set jpegLib [$cc compile]
Claim the jpeg library is $jpegLib
}
}
<unknown> claims builtin-programs/image/image-lib.folk has program code {set cc [C]
$cc include <stdl (
[ m78:0 (s122:0) ]
)<unknown> claims builtin-programs/image/image-lib.folk has program code {set cc [C]
$cc include <stdlib.h>
$cc include <string.h>
$cc struct Image {
uint32_t width;
uint32_t height;
int components;
uint32_t bytesPerRow;
// Weird: this can be mutated if you want the image to be
// reloaded into the GPU.
uint64_t uniq;
uint8_t* data;
}
# Note that this returns an image whose lifetime is tied to the original image.
$cc proc slice {Image im double x double y double subwidth double subheight} Image {
uint8_t *subdata = im.data + (int)y*im.bytesPerRow + (int)x*im.components;
return (Image) {
.width = (uint32_t)subwidth,
.height = (uint32_t)subheight,
.components = im.components,
.bytesPerRow = im.bytesPerRow,
.data = subdata,
.uniq = im.uniq
};
}
$cc proc imageNew {int width int height int components int uniq} Image {
uint8_t* data = malloc(width*components*height);
return (Image) {
.width = width,
.height = height,
.components = components,
.bytesPerRow = width*components,
.data = data,
.uniq = uniq
};
}
$cc proc imageFree {Image image} void {
free(image.data);
}
# Note that this returns a fresh (copied) image. imVertices are
# coordinates in im, clockwise from top-left.
$cc proc warpQuad {Image im double[4][2] imVertices
int outWidth int outHeight} Image {
if (outWidth <= 0 || outHeight <= 0 ||
outWidth > (int)im.width * 4 || outHeight > (int)im.height * 4) {
FOLK_ERROR("warpQuad: bad dimensions %d x %d (source %d x %d)",
outWidth, outHeight, im.width, im.height);
}
Image out = imageNew(outWidth, outHeight, im.components, im.uniq);
// imVertices are clockwise from top-left: [TL, TR, BR, BL]
double tlX = imVertices[0][0], tlY = imVertices[0][1];
double trX = imVertices[1][0], trY = imVertices[1][1];
double brX = imVertices[2][0], brY = imVertices[2][1];
double blX = imVertices[3][0], blY = imVertices[3][1];
// For each output pixel, find corresponding source pixel using bilinear mapping
double invW = (outWidth > 1) ? 1.0 / (outWidth - 1) : 0.0;
double invH = (outHeight > 1) ? 1.0 / (outHeight - 1) : 0.0;
for (int y = 0; y < outHeight; y++) {
// Hoist v and y-dependent edge coords outside x-loop
double v = y * invH;
double leftX = tlX + v * (blX - tlX);
double leftY = tlY + v * (blY - tlY);
double rightX = trX + v * (brX - trX);
double rightY = trY + v * (brY - trY);
double stepX = (rightX - leftX) * invW;
double stepY = (rightY - leftY) * invW;
uint8_t *dstRow = out.data + y * out.bytesPerRow;
double srcX = leftX, srcY = leftY;
for (int x = 0; x < outWidth; x++, srcX += stepX, srcY += stepY) {
uint8_t *dstPixel = dstRow + x * out.components;
int ix = (int)srcX;
int iy = (int)srcY;
// Fixed-point fractions (0..255)
int fx = (int)((srcX - ix) * 256);
int fy = (int)((srcY - iy) * 256);
if (ix >= 0 && ix < (int)im.width - 1 && iy >= 0 && iy < (int)im.height - 1) {
uint8_t *p00 = im.data + iy * im.bytesPerRow + ix * im.components;
uint8_t *p10 = p00 + im.components;
uint8_t *p01 = p00 + im.bytesPerRow;
uint8_t *p11 = p01 + im.components;
for (int c = 0; c < im.components; c++) {
int top = p00[c] + ((fx * (p10[c] - p00[c])) >> 8);
int bot = p01[c] + ((fx * (p11[c] - p01[c])) >> 8);
dstPixel[c] = (uint8_t)(top + ((fy * (bot - top)) >> 8));
}
} else if (ix >= 0 && ix < (int)im.width && iy >= 0 && iy < (int)im.height) {
uint8_t *srcPixel = im.data + iy * im.bytesPerRow + ix * im.components;
for (int c = 0; c < im.components; c++) {
dstPixel[c] = srcPixel[c];
}
} else {
for (int c = 0; c < im.components; c++) {
dstPixel[c] = 0;
}
}
}
}
return out;
}
set imageLib [$cc compile]
Claim the image library is $imageLib
fn defineImageArgtype {uvx} {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
}
Claim the image uvx argtype definer is [fn defineImageArgtype]
}
<unknown> claims builtin-programs/image/png-lib.folk has program code {When the image library is /ima (
[ m80:0 (s124:0) ]
)<unknown> claims builtin-programs/image/png-lib.folk has program code {When the image library is /imageLib/ {
set cc [C]
$cc extend $imageLib
$cc endcflags -lpng
$cc include <stdlib.h>
$cc include <string.h>
$cc code {
#undef EXTERN
#include <png.h>
#include <stdint.h>
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);
if (components == 3)
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 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 FOLK_ERROR("Unsupported number of components");
png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = data + i * bytesPerRow;
}
png_init_io(png_w, dest);
png_set_rows(png_w, info_w, row_pointers);
png_write_png(png_w, info_w, PNG_TRANSFORM_IDENTITY, NULL);
free(row_pointers);
}
}
$cc proc saveAsPng {Image im char* filename} void {
FILE* out = fopen(filename, "wb");
FOLK_ENSURE(out != NULL);
png(out, im.data, im.components, im.bytesPerRow, im.width, im.height);
fclose(out);
}
$cc proc loadPng {char* filename} Image {
FILE* file = fopen(filename, "rb");
if (!file) {
FOLK_ERROR("Error opening file: %s\n", filename);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
FOLK_ERROR("Error reading png from file: %s it's not a png\n", filename);
}
png_infop info = png_create_info_struct(png);
if(!info) {
FOLK_ERROR("Error reading png from file: %s no info?\n", filename);
}
if(setjmp(png_jmpbuf(png))) {
FOLK_ERROR("Error reading png from file: %s setjmp error?\n", filename);
}
png_init_io(png, file);
png_read_info(png, info);
Image ret;
ret.width = png_get_image_width(png, info);
ret.height = png_get_image_height(png, info);
int bytes_per_pixel = png_get_channels(png, info);
ret.components = png_get_channels(png, info);
ret.bytesPerRow = ret.width * bytes_per_pixel;
ret.data = malloc(ret.bytesPerRow * ret.height);
// Iterate over the rows and read the image data into the buffer.
for (int i = 0; i < ret.height; i++) {
png_read_row(png, ret.data + (i * ret.bytesPerRow), NULL);
}
// Close the PNG file.
png_destroy_read_struct(&png, &info, NULL);
if (ret.components == 4) {
// Transcode from RGBA to RGB (we don't support RGBA yet.)
for(int i=0; i < ret.width*ret.height; i++) {
int r = ret.data[i*4+0],
g = ret.data[i*4+1],
b = ret.data[i*4+2],
a = ret.data[i*4+3];
ret.data[i*3+0] = r * a / 255;
ret.data[i*3+1] = g * a / 255;
ret.data[i*3+2] = b * a / 255;
}
ret.components = 3;
ret.bytesPerRow = ret.width * ret.components;
}
return ret;
}
set pngLib [$cc compile]
Claim the png library is $pngLib
}
}
<unknown> claims builtin-programs/print/print.folk has program code #\ Configuring\ printers\n#\n#\ S (
[ m83:0 (s127:0) ]
)<unknown> claims builtin-programs/print/print.folk has program code #\ Configuring\ printers\n#\n#\ Start\ by\ adding\ a\ printer\ to\ CUPS.\ You\ can\ do\ this\ from\ the\ Web\ UI,\ or\ declare\ it\ using\ Folk:\n#\n#\ \ \ \ \ Assert\ \$::thisNode\ claims\ printer\ \"printer-name\"\ is\ a\ cups\ printer\ with\ url\ \"http://url/ipp/print\"\ driver\ \"everywhere\"\n#\n#\ Lastly,\ you\ need\ to\ declare\ a\ default\ printer\ and\ default\ paper\ format:\n#\ (make\ sure\ that\ the\ default\ printer\ supports\ the\ default\ paper\ format)\n#\n#\ \ \ \ \ Claim\ printer\ my-printer\ is\ the\ default\ printer\n#\ \ \ \ \ Claim\ paper\ format\ a4\ is\ the\ default\ paper\ format\n\nClaim\ the\ paper\ formats\ are\ \{\n\ \ \ \ letter\ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\ \ \ \ a4\ \ \ \ \ \ \ \ \{tagInnerSideLength\ 70\ pageSize\ \{595\ 842\}\}\n\ \ \ \ indexcard\ \{tagInnerSideLength\ 70\ pageSize\ \{612\ 792\}\}\n\}\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /saveDir/\ \{\nfn\ configCcWithLibapriltag\n\nset\ cc\ \[C\]\n\$cc\ extend\ \$imageLib\n\$cc\ cflags\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ code\ \{\n\ \ \ \ #include\ <apriltag.h>\n\ \ \ \ #include\ <tagStandard52h13.h>\n\ \ \ \ apriltag_family_t\ *tf\ =\ NULL\;\n\}\n\n#\ HACK\ (osnr):\ This\ is\ used\ when\ someone\ wants\ to\ draw\ an\ AprilTag\n#\ (often\ for\ calibration/cnc\ preview\ purposes)\;\ I\ put\ it\ here\ because\n#\ we\ already\ have\ a\ whole\ AprilTag\ family\ and\ C\ compiler\ object\ setup\n#\ here.\ The\ returned\ image_t's\ data\ needs\ to\ be\ freed\ by\ the\ caller.\n\$cc\ proc\ tagImageForId\ \{int\ id\}\ Image\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\ \ \ \ Image\ ret\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ image->width,\ .height\ =\ image->height,\n\ \ \ \ \ \ \ \ .components\ =\ 1,\ .bytesPerRow\ =\ image->stride,\n\ \ \ \ \ \ \ \ .data\ =\ image->buf\n\ \ \ \ \}\;\n\ \ \ \ free(image)\;\ //\ doesn't\ free\ data\n\ \ \ \ return\ ret\;\n\}\n\n\$cc\ proc\ tagPsForId\ \{int\ id\}\ char*\ \{\n\ \ \ \ if\ (tf\ ==\ NULL)\ tf\ =\ tagStandard52h13_create()\;\n\n\ \ \ \ image_u8_t*\ image\ =\ apriltag_to_image(tf,\ id)\;\n\n\ \ \ \ char*\ ret\ =\ malloc(10000)\;\n#define\ emit(...)\ i\ +=\ sprintf(&ret\[i\],\ __VA_ARGS__)\n\ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ emit(\"gsave\\n\")\;\n\ \ \ \ emit(\"0\ 1\ translate\\n\")\;\n\ \ \ \ emit(\"%f\ %f\ scale\\n\",\ 1.0/image->width,\ -1.0/image->height)\;\n\ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ image->height\;\ row++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ image->width\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pixel\ =\ image->buf\[(row\ *\ image->stride)\ +\ col\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ setgray\ \",\ pixel\ !=\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"newpath\ \")\;\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ moveto\ \",\ col,\ row)\;\ //\ bottom-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row)\;\ //\ bottom-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col\ +\ 1,\ row\ +\ 1)\;\ //\ top-right\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"%d\ %d\ lineto\ \",\ col,\ row\ +\ 1)\;\ //\ top-left\n\ \ \ \ \ \ \ \ \ \ \ \ emit(\"closepath\ fill\ \")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ emit(\"\\n\")\;\n\ \ \ \ \}\n\ \ \ \ emit(\"grestore\\n\")\;\n#undef\ emit\n\ \ \ \ ret\[i++\]\ =\ '\\0'\;\n\ \ \ \ image_u8_destroy(image)\;\n\ \ \ \ return\ ret\;\n\}\nset\ printLib\ \[\$cc\ compile\]\nClaim\ the\ print\ library\ is\ \$printLib\n\nfn\ codeToPostScript\ \{id\ code\ opts\ \{marginsVar\ \{\}\}\}\ \{\n\ \ \ \ #\ All\ opts\ should\ be\ passed\ in\ as\ points\ (1/2834.65\ of\ a\ meter).\n\ \ \ \ lassign\ \$opts(pageSize)\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInnerSideLength\ \$opts(tagInnerSideLength)\n\ \ \ \ set\ tagWidth\ \[expr\ \{\$tagInnerSideLength\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ tagHeight\ \$tagWidth\n\ \ \ \ lassign\ \$opts(margin)\ marginTop\ marginRight\ marginBottom\ marginLeft\n\ \ \ \ set\ tagInset\ \$opts(tagInset)\n\ \ \ \ set\ lineHeight\ \$opts(lineHeight)\n\n\ \ \ \ #\ The\ calibration\ concat\ \[s\ 0\ 0\ s\ tx\ ty\]\ maps\ our\ user\ coords\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coords.\ Anything\ outside\ the\ raw\n\ \ \ \ #\ \[0,PageWidth\]x\[0,PageHeight\]\ is\ clipped,\ so\ the\ effective\n\ \ \ \ #\ printable\ area\ in\ user\ coords\ is\ smaller\ than\ the\ full\ page.\n\ \ \ \ set\ calibScale\ \[dict\ getdef\ \$opts\ calibratedPrintScale\ 1.0\]\n\ \ \ \ lassign\ \[dict\ getdef\ \$opts\ calibratedPrintTranslation\ \{0\ 0\}\]\ calibTx\ calibTy\n\ \ \ \ set\ effTop\ \ \ \ \[expr\ \{(\$PageHeight\ -\ \$calibTy)\ /\ \$calibScale\}\]\n\ \ \ \ set\ effBottom\ \[expr\ \{-\$calibTy\ /\ \$calibScale\}\]\n\ \ \ \ set\ effLeft\ \ \ \[expr\ \{-\$calibTx\ /\ \$calibScale\}\]\n\ \ \ \ set\ effRight\ \ \[expr\ \{(\$PageWidth\ -\ \$calibTx)\ /\ \$calibScale\}\]\n\n\ \ \ \ #\ Effective\ margins,\ measured\ from\ the\ physical\ paper\ edge.\ The\n\ \ \ \ #\ intent\ of\ marginTop/etc\ is\ \"this\ far\ from\ the\ paper\ edge\".\ If\ the\n\ \ \ \ #\ printer's\ unprintable\ margin\ already\ exceeds\ that,\ clamp\ to\ the\n\ \ \ \ #\ printable\ edge\ (rather\ than\ adding\ the\ two,\ which\ would\ push\n\ \ \ \ #\ content\ way\ inward).\n\ \ \ \ if\ \{\$marginsVar\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ upvar\ \$marginsVar\ effMargins\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ effMargins\ \{\}\n\ \ \ \ \}\n\ \ \ \ set\ effMargins(top)\ \ \ \ \[::math::max\ \$marginTop\ \[expr\ \{\$PageHeight\ -\ \$effTop\}\]\]\n\ \ \ \ set\ effMargins(bottom)\ \[::math::max\ \$marginBottom\ \$effBottom\]\n\ \ \ \ set\ effMargins(left)\ \ \ \[::math::max\ \$marginLeft\ \$effLeft\]\n\ \ \ \ set\ effMargins(right)\ \ \[::math::max\ \$marginRight\ \[expr\ \{\$PageWidth\ -\ \$effRight\}\]\]\n\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$effMargins(top)\ -\ \$effMargins(bottom))\ /\ \$lineHeight)\}\]\n\n\ \ \ \ set\ lineNumbersRight\ \[expr\ \{\$effMargins(left)\ +\ \$opts(advance)*1.5\}\]\n\n\ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\n\ \ \ \ set\ image\ \[\$printLib\ tagPsForId\ \$id\]\n\n\ \ \ \ set\ outPages\ \[list\]\n\ \ \ \ set\ lineIdx\ 0\n\ \ \ \ while\ \{\[llength\ \$lines\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ pageLines\ \[lrange\ \$lines\ 0\ \$maxLines-1\]\n\ \ \ \ \ \ \ \ set\ lines\ \[lreplace\ \$lines\ 0\ \$maxLines-1\]\n\n\ \ \ \ \ \ \ \ set\ pageLineIdx\ 0\n\ \ \ \ \ \ \ \ #\ The\ typesetting\ here\ is\ meant\ to\ exactly\ duplicate\ the\n\ \ \ \ \ \ \ \ #\ layout\ in\ the\ editor.\n\ \ \ \ \ \ \ \ lappend\ outPages\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ \ \ \ \ \\\[\$calibScale\ 0\ 0\ \$calibScale\ \$calibTx\ \$calibTy\\\]\ concat\n\n\ \ \ \ \ \ \ \ \ \ \ \ /settextcolor\ \{0\ setgray\}\ def\n\n\ \ \ \ \ \ \ \ \ \ \ \ /NeomatrixCode\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \$lineHeight\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ setfont\n\n\ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ line\ \$pageLines\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\ \")\"\ \"\\\\)\"\ \"(\"\ \"\\\\(\"\}\ \$line\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ lineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ pageLineIdx\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$lineNumbersRight\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.6\ setgray\ (\[format\ \"%\ 3s\"\ \$lineIdx\])\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dup\ stringwidth\ pop\ neg\ 0\ rmoveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ show\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[+\ \$lineNumbersRight\ \$opts(advance)\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$pageLineIdx*\$lineHeight\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ settextcolor\ (\$line)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\[llength\ \$outPages\]\ >\ 0\ ?\ \{\}\ :\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-\$tagInset\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagWidth\ \$tagHeight\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$image\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica-Narrow\ findfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 7\ scalefont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth-\$effMargins(right)-\$tagWidth-\$tagInset\}\]\ \[expr\ \{\$PageHeight-\$effMargins(top)-\$tagHeight-14-\$tagInset\}\]\ moveto\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$id\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%a,\ %d\ %b\ %Y,\ %r\"\]))\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ showpage\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[join\ \$outPages\ \"\\n\"\]\n\}\nClaim\ the\ codeToPostScript\ is\ \[fn\ codeToPostScript\]\n\nfn\ nextId\ \{\}\ \{\n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n\}\nWhen\ \$::thisNode\ claims\ printer\ /name/\ is\ a\ cups\ printer\ with\ /...options/\ \{\n\ \ \ \ set\ command\ \[list\ /usr/sbin/lpadmin\ -p\ \$name\ -E\]\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ url\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -v\ \[dict\ get\ \$options\ url\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ driver\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ -m\ \[dict\ get\ \$options\ driver\]\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ extra-args\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ command\ \{*\}\[dict\ get\ \$options\ extra-args\]\n\ \ \ \ \}\n\n\ \ \ \ exec\ \{*\}\$command\n\}\n\nSubscribe:\ print\ code\ /code/\ \{\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ a\ new\ program\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n\}\nSubscribe:\ print\ program\ /id/\ with\ /...options/\ \{\n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n\}\n\n\}\n\nSubscribe:\ print\ pdf\ /pdfPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n\}\n
<unknown> claims builtin-programs/web/setup.folk has program code Wish\ the\ web\ server\ handles\ ro (
[ m85:0 (s136:0) ]
)<unknown> claims builtin-programs/web/setup.folk has program code Wish\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ nav\ \"<button>Setup</button>\"\ handler\ \{\n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n\}\n
<unknown> claims builtin-programs/web/dep-graph.folk has program code set\ dbDotify\ \{\{dbLib\ db\}\ (
[ m86:0 (s132:0) ]
)<unknown> claims builtin-programs/web/dep-graph.folk has program code set\ dbDotify\ \{\{dbLib\ db\}\ \{\n\ \ \ \ set\ dot\ \[list\]\n\ \ \ \ set\ matchRefs\ \[dict\ create\]\n\ \ \ \ foreach\ stmt\ \[Query!\ /...anything/\]\ \{\n\ \ \ \ \ \ \ \ set\ stmtRef\ \[dict\ get\ \$stmt\ __ref\]\n\ \ \ \ \ \ \ \ set\ label\ \[\$dbLib\ clause\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ label\ \[join\ \[lmap\ line\ \[split\ \$label\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ set\ label\ \[string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$label\]\]\n\ \ \ \ \ \ \ \ set\ stmtParentCount\ \[\$dbLib\ statementParentCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ set\ stmtPtrCount\ \[\$dbLib\ statementPtrCount\ \$db\ \$stmtRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ \\\[label=\\\"\$stmtRef\ (\$stmtParentCount\ parents)\ (\$stmtPtrCount\ ptrs):\ \$label\\\"\\\]\;\"\n\n\ \ \ \ \ \ \ \ foreach\ childMatchRef\ \[\$dbLib\ childMatches\ \$db\ \$stmtRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$stmtRef>\ ->\ <\$childMatchRef>\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ matchRefs\ \$childMatchRef\ true\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ foreach\ \{matchRef\ _\}\ \$matchRefs\ \{\n\ \ \ \ \ \ \ \ set\ match\ \[\$dbLib\ matchAcq\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ if\ \{\$match\ eq\ \"(Match*)\ 0x0\"\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ set\ matchPtrCount\ \[\$dbLib\ matchPtrCount\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ set\ matchIsAlive\ \[\$dbLib\ matchIsAlive\ \$db\ \$matchRef\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ \\\[label=\\\"\$matchRef\ (alive?\ \$matchIsAlive)\ (\$matchPtrCount)\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ childStatementRef\ \[\$dbLib\ childStatements\ \$db\ \$matchRef\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"<\$matchRef>\ ->\ <\$childStatementRef>\;\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$dbLib\ matchRel\ \$db\ \$match\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[join\ \$dot\ \"\\n\"\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWhen\ the\ db\ library\ is\ /dbLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/dep-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/web/nav.folk has program code {When the collected results for [list (
[ m87:0 (s133:0) ]
)<unknown> claims builtin-programs/web/nav.folk has program code {When the collected results for [list /someone/ wishes the web server handles route /route/ with /...options/] are /handlers/ {
# Generate navigation from all route handlers.
set navLinks [list]
foreach handler $handlers {
set route $handler(route)
if {[dict getdef $handler(options) hidden false]} { continue }
if {$route eq "/"} { continue }
# Filter out routes with non-optional capture groups.
# Check if route has capturing groups (not non-capturing (?:...)).
set hasCapturingGroup [regexp {\([^?]} $route]
# Check if ANY group is non-optional (has ) not followed by ?).
set hasNonOptionalGroup [regexp {\)[^?]} $route]
if {$hasCapturingGroup && $hasNonOptionalGroup} { continue }
# Remove all regex patterns and capture groups for the href and
# display name.
set route [regsub -all {\([^)]*\)} $route ""]
set route [regsub -all {\[[^\]]*\]} $route ""]
# Convert escaped dots to plain dots first
set route [regsub -all {\\.} $route "."]
# Remove wildcard patterns like .* and .+
set route [regsub -all {\.\*} $route ""]
set route [regsub -all {\.\+} $route ""]
# Remove other regex metacharacters (but not .)
set route [regsub -all {[\\?*+^]} $route ""]
set route [regsub {\$$} $route ""]
set route [regsub {\$\s*$} $route ""]
# Create a nice display name from the route.
set displayName [string trim $route "/"]
set displayName [string map {"-" " " ".pdf" "" "_" " "} $displayName]
set displayName [string totitle $displayName]
set nav [dict getdef $handler(options) nav $displayName]
lappend navLinks "<a href=\"$route\">$nav</a>"
}
Claim the web navigation HTML is [subst {
<nav>
[join $navLinks "\n "]
</nav>
}]
}
}
<unknown> claims builtin-programs/web/textures.folk has program code When\ the\ GPU\ library\ is\ /gp (
[ m90:0 (s143:0) ]
)<unknown> claims builtin-programs/web/textures.folk has program code When\ the\ GPU\ library\ is\ /gpuLib/\ &\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ draw\ library\ is\ /drawLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ endcflags\ -lpng\n\ \ \ \ \$cc\ cflags\ -I./vendor\n\ \ \ \ \$cc\ endcflags\ \$vmaDll\n\ \ \ \ \$cc\ include\ <png.h>\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ \ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ \ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ to\ make\ gpuLib\ extend\ properly\n\ \ \ \ \$cc\ typedef\ \{struct\ PushConstantsEncoder\}\ PushConstantsEncoder\n\ \ \ \ \$cc\ typedef\ \{struct\ Pipeline\}\ Pipeline\n\ \ \ \ \$cc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\ \ \ \ \$cc\ argtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ \ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ rtype\ VmaAllocation\ \{\n\ \ \ \ \ \ \ \ char\ buf\[100\]\;\n\ \ \ \ \ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ extend\ \$gpuLib\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ extend\ \$gpuTextureLib\n\ \ \ \ \$cc\ proc\ texturesLibInit\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ volkInitialize()\;\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyTextureFromGpu\ \{GpuTextureHandle\ han\}\ Image\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ getGpuTexture(han)\;\n\ \ \ \ \ \ \ \ if\ (!block->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (Image)\{0\}\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ block->width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ block->height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\ //\ HACK:\ hard-coded\ for\ now\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ block->width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ malloc(block->width\ *\ block->height\ *\ 4)\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ size_t\ stagingBufferSize\ =\ block->width\ *\ block->height\ *\ 4\;\n\ \ \ \ \ \ \ \ createBuffer(stagingBufferSize,\ VK_BUFFER_USAGE_TRANSFER_DST_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &stagingBuffer,\ &stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,\n\ \ \ \ \ \ \ \ \ \ \ \ .oldLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED,\n\ \ \ \ \ \ \ \ \ \ \ \ .image\ =\ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseMipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.levelCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .subresourceRange.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .srcAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .dstAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ image\ to\ buffer\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferOffset\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferRowLength\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .bufferImageHeight\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.mipLevel\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.baseArrayLayer\ =\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageSubresource.layerCount\ =\ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ .imageOffset\ =\ \{0,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ .imageExtent\ =\ \{block->width,\ block->height,\ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ vkCmdCopyImageToBuffer(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ ®ion\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ image\ layout\ back\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_READ_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(\n\ \ \ \ \ \ \ \ \ \ \ \ commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier\n\ \ \ \ \ \ \ \ )\;\n\n\ \ \ \ \ \ \ \ VkFence\ fence\ =\ getFence()\;\n\ \ \ \ \ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ staging\ buffer\ back\ to\ CPU\n\ \ \ \ \ \ \ \ void*\ data\;\n\ \ \ \ \ \ \ \ vmaMapMemory(vmaGetAllocator(),\ stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ memcpy(im.data,\ data,\ stagingBufferSize)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ //\ Cleanup\ staging\ buffer\n\ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\ stagingBuffer,\ stagingBufferAllocation)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ struct\ WriteState\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ buffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t*\ size\;\ \n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ void\ pngWriteCallback(png_structp\ png_ptr,\ png_bytep\ data,\ png_size_t\ length)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ WriteState*\ state\ =\ (struct\ WriteState*)png_get_io_ptr(png_ptr)\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(state->buffer\ +\ *state->size,\ data,\ length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ *state->size\ +=\ length\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ imageToPngBuffer\ \{Image\ im\ size_t*\ outSize\}\ uint8_t*\ \{\n\ \ \ \ \ \ \ \ size_t\ bufferSize\ =\ im.width\ *\ im.height\ *\ im.components\ *\ 2\;\ //\ max\ size\ estimate\n\ \ \ \ \ \ \ \ uint8_t*\ buffer\ =\ malloc(bufferSize)\;\n\ \ \ \ \ \ \ \ *outSize\ =\ 0\;\n\n\ \ \ \ \ \ \ \ png_structp\ png_w\ =\ png_create_write_struct(PNG_LIBPNG_VER_STRING,\ NULL,\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (!png_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_infop\ info_w\ =\ png_create_info_struct(png_w)\;\n\ \ \ \ \ \ \ \ if\ (!info_w)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ struct\ WriteState\ state\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .buffer\ =\ buffer,\n\ \ \ \ \ \ \ \ \ \ \ \ .size\ =\ outSize\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ png_set_write_fn(png_w,\ &state,\ pngWriteCallback,\ NULL)\;\n\n\ \ \ \ \ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGBA,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_set_IHDR(png_w,\ info_w,\ im.width,\ im.height,\ 8,\ PNG_COLOR_TYPE_RGB,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_INTERLACE_NONE,\ PNG_COMPRESSION_TYPE_DEFAULT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PNG_FILTER_TYPE_DEFAULT)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(buffer)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ NULL\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_bytep*\ row_pointers\ =\ malloc(sizeof(png_bytep)\ *\ im.height)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ row_pointers\[y\]\ =\ im.data\ +\ y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ png_set_rows(png_w,\ info_w,\ row_pointers)\;\n\ \ \ \ \ \ \ \ png_write_png(png_w,\ info_w,\ PNG_TRANSFORM_IDENTITY,\ NULL)\;\n\n\ \ \ \ \ \ \ \ free(row_pointers)\;\n\ \ \ \ \ \ \ \ png_destroy_write_struct(&png_w,\ &info_w)\;\n\n\ \ \ \ \ \ \ \ *outSize\ =\ bufferSize\;\n\ \ \ \ \ \ \ \ return\ buffer\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ proc\ copyAllTexturesFromGpu\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (getGpuTexture(i)->alive)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Image\ im\ =\ copyTextureFromGpu(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pngSize\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t*\ pngData\ =\ imageToPngBuffer(im,\ &pngSize)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_ObjPrintf(\"Image\ %d\ (%d\ x\ %d)\",\ i,\ im.width,\ im.height))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ Jim_NewStringObj(interp,\ (char*)pngData,\ pngSize))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(pngData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(im.data)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ set\ texturesLib\ \[\$cc\ compile\]\n\ \ \ \ \$texturesLib\ texturesLibInit\n\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/textures\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ package\ require\ base64\n\n\ \ \ \ \ \ \ \ set\ images\ \[\$texturesLib\ copyAllTexturesFromGpu\]\n\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>Textures</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ img\ \{\ max-width:\ 100%\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{description\ imageData\}\ \$images\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ b64\ \[binary\ encode\ base64\ \$imageData\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \{<div><p>%s</p><img\ src=\"data:image/png\;base64,%s\"></div>\}\ \$description\ \$b64\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/web/block-stats.folk has program code {Wish the web server handles (
[ m92:0 (s141:0) ]
)<unknown> claims builtin-programs/web/block-stats.folk has program code {Wish the web server handles route "/block-stats" with handler {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
}
}
<unknown> claims builtin-programs/web/program.folk has program code {Wish the web server handles rout (
[ m93:0 (s145:0) ]
)<unknown> claims builtin-programs/web/program.folk has program code {Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
}
}
<unknown> claims builtin-programs/web/holds.folk has program code {When the db library is /dbLib/ {
(
[ m95:0 (s147:0) ]
)<unknown> claims builtin-programs/web/holds.folk has program code {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/holds" with handler {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
}
}
}
<unknown> claims builtin-programs/web/db-lib.folk has program code {Claim the db library is [apply {{ (
[ m99:0 (s151:0) ]
)<unknown> claims builtin-programs/web/db-lib.folk has program code {Claim the db library is [apply {{} {
set cc [C]
$cc cflags -I. -I./vendor/tracy/public
$cc include "db.h"
$cc include "common.h"
$cc include "vendor/stb_ds.h"
$cc code {
typedef struct ListOfEdgeTo {
size_t capacityEdges;
size_t nEdges; // This is an estimate.
uint64_t edges[];
} ListOfEdgeTo;
typedef struct GenRc {
int16_t rc;
int gen: 15;
bool alive: 1;
} GenRc;
#include <pthread.h>
}
set dbCFd [open "db.c" r]; set dbC [read $dbCFd]; close $dbCFd
$cc code [lindex [regexp -inline {typedef struct Destructor \{.*\} Destructor;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct DestructorSet \{.*\} DestructorSet;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Statement \{.*\} Statement;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Match \{.*\} Match;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Hold \{.*\} Hold;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct StatementRefList \{.*\} StatementRefList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersionList \{.*\} AtomicallyVersionList;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct AtomicallyVersion \{.*\} AtomicallyVersion;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Atomically \{.*\} Atomically;} $dbC] 0]
$cc code [lindex [regexp -inline {typedef struct Db \{.*\} Db;} $dbC] 0]
$cc argtype StatementRef { StatementRef $argname; sscanf(Jim_String($obj), "s%d:%d", &$argname.idx, &$argname.gen); }
$cc argtype MatchRef { MatchRef $argname; sscanf(Jim_String($obj), "m%d:%d", &$argname.idx, &$argname.gen); }
$cc proc clauseToJimObj {Clause* clause} Jim_Obj* {
Jim_Obj* termObjs[clause->nTerms];
for (int i = 0; i < clause->nTerms; i++) {
termObjs[i] = Jim_NewStringObj(interp, termPtr(clause->terms[i]),
termLen(clause->terms[i]));
}
return Jim_NewListObj(interp, termObjs, clause->nTerms);
}
$cc proc statementParentCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
int ret = stmt->parentCount;
statementRelease(db, stmt);
return ret;
}
$cc proc statementPtrCount {Db* db StatementRef stmtRef} int {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return -1; }
GenRc genRc = stmt->genRc;
int ret = genRc.rc - 1;
statementRelease(db, stmt);
return ret;
}
$cc proc clause {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewStringObj(interp, "(null)", -1); }
Jim_Obj* ret = clauseToJimObj(statementClause(stmt));
statementRelease(db, stmt);
return ret;
}
$cc proc childMatches {Db* db StatementRef stmtRef} Jim_Obj* {
Statement* stmt = statementAcquire(db, stmtRef);
if (stmt == NULL) { return Jim_NewEmptyStringObj(interp); }
pthread_mutex_lock(&stmt->childMatchesMutex);
if (stmt->childMatches == NULL) {
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[stmt->childMatches->nEdges];
for (int i = 0; i < stmt->childMatches->nEdges; i++) {
MatchRef child = { .val = stmt->childMatches->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("m%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&stmt->childMatchesMutex);
statementRelease(db, stmt);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc matchAcq {Db* db MatchRef matchRef} Match* {
return matchAcquire(db, matchRef);
}
$cc proc matchRel {Db* db Match* match} void {
matchRelease(db, match);
}
$cc proc matchPtrCount {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int ret = genRc.rc - 1;
matchRelease(db, match);
return ret;
}
$cc proc matchIsAlive {Db* db MatchRef matchRef} int {
Match* match = matchAcquire(db, matchRef);
GenRc genRc = match->genRc;
int alive = genRc.alive;
matchRelease(db, match);
return alive;
}
$cc code {
#define CHILD_STATEMENTS_REMOVING ((ListOfEdgeTo*)1)
}
$cc proc childStatements {Db* db MatchRef matchRef} Jim_Obj* {
Match* match = matchAcquire(db, matchRef);
if (match == NULL) { return Jim_NewStringObj(interp, "", -1); }
pthread_mutex_lock(&match->childStatementsMutex);
if (match->childStatements == NULL ||
match->childStatements == CHILD_STATEMENTS_REMOVING) {
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewEmptyStringObj(interp);
}
int nChildren = 0;
Jim_Obj* childObjs[match->childStatements->nEdges];
for (int i = 0; i < match->childStatements->nEdges; i++) {
StatementRef child = { .val = match->childStatements->edges[i] };
childObjs[nChildren++] = Jim_ObjPrintf("s%d:%d", child.idx, child.gen);
}
pthread_mutex_unlock(&match->childStatementsMutex);
matchRelease(db, match);
return Jim_NewListObj(interp, childObjs, nChildren);
}
$cc proc countAliveStatements {Db* db} int {
int count = 0;
for (int i = 1; i < 65536; i++) { // slot 0 is reserved
GenRc genRc = db->statementPool[i].genRc;
if (genRc.alive) {
count++;
}
}
return count;
}
$cc proc holds {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->holdsMutex);
for (int i = 0; i < shlen(db->holds); i++) {
Hold* hold = &db->holds[i];
Statement* stmt = statementAcquire(db, hold->statement);
if (stmt == NULL) {
fprintf(stderr, "db-lib: holds: WARNING: held statement on (%s) is invalid! (s%d:%d)\n",
hold->key, hold->statement.idx, hold->statement.gen);
continue;
}
char* clauseStr = clauseToString(statementClause(stmt));
Jim_Obj* holdObjv[] = {
Jim_NewStringObj(interp, hold->key, -1),
Jim_NewIntObj(interp, hold->version),
Jim_ObjPrintf("s%d:%d", hold->statement.idx, hold->statement.gen),
Jim_NewStringObj(interp, clauseStr, -1)
};
statementRelease(db, stmt);
free(clauseStr);
Jim_Obj* holdObj = Jim_NewListObj(interp, holdObjv,
sizeof(holdObjv)/sizeof(holdObjv[0]));
Jim_ListAppendElement(interp, retObj, holdObj);
}
mutexUnlock(&db->holdsMutex);
return retObj;
}
$cc proc atomicallys {Db* db} Jim_Obj* {
Jim_Obj* retObj = Jim_NewListObj(interp, NULL, 0);
mutexLock(&db->atomicallysMutex);
for (int i = 0; i < sizeof(db->atomicallys)/sizeof(db->atomicallys[0]); i++) {
Atomically* atomically = &db->atomicallys[i];
if (atomically->key == NULL) { continue; }
// Count versions in allVersions list
int versionCount = 0;
AtomicallyVersionList* vl = atomically->allVersions;
while (vl != NULL) {
versionCount++;
vl = vl->next;
}
// Get latest converged version info
int latestConvergedNumber = -1;
if (atomically->latestConvergedVersion != NULL) {
latestConvergedNumber = atomically->latestConvergedVersion->number;
}
Jim_Obj* atomicallyObjv[] = {
Jim_NewStringObj(interp, atomically->key, -1),
Jim_NewIntObj(interp, latestConvergedNumber),
Jim_NewIntObj(interp, versionCount)
};
Jim_Obj* atomicallyObj = Jim_NewListObj(interp, atomicallyObjv,
sizeof(atomicallyObjv)/sizeof(atomicallyObjv[0]));
Jim_ListAppendElement(interp, retObj, atomicallyObj);
}
mutexUnlock(&db->atomicallysMutex);
return retObj;
}
return [$cc compile]
}}]
}
<unknown> claims builtin-programs/web/threads.folk has program code set\ threadMonitorLib\ \[apply\ \ (
[ m101:0 (s154:0) ]
)<unknown> claims builtin-programs/web/threads.folk has program code set\ threadMonitorLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ -I./vendor/tracy/public\n\ \ \ \ \$cc\ include\ \"workqueue.h\"\n\ \ \ \ \$cc\ include\ \"common.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ extern\ ThreadControlBlock\ threads\[\]\;\n\ \ \ \ \ \ \ \ extern\ int\ _Atomic\ threadCount\;\n\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ int\ unsafe_workQueueCopy(WorkQueueItem*\ into,\ int\ maxn,\ WorkQueue*\ q)\;\n\ \ \ \ \ \ \ \ extern\ void\ traceItem(char*\ buf,\ size_t\ bufsz,\ WorkQueueItem\ item)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ itemToStringObj(WorkQueueItem\ item)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ char\ buf\[10000\]\;\ traceItem(buf,\ sizeof(buf),\ item)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerTids\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ //\ Fallback\ on\ macOS,\ where\ we\ don't\ have\ /proc\ to\ query\ all\n\ \ \ \ \ \ \ \ //\ threads\ of\ the\ Folk\ process.\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ threads\[i\].tid))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfo\ \{int\ threadIndex\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ if\ (threadIndex\ >=\ threadCount\ ||\ threads\[threadIndex\].tid\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ ThreadControlBlock\ *thread\ =\ &threads\[threadIndex\]\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ thread->currentItem\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\ Jim_NewStringObj(interp,\ \"op\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(item))\;\n\n\ \ \ \ \ \ \ \ WorkQueueItem\ items\[100\]\;\n\ \ \ \ \ \ \ \ int\ nitems\ =\ unsafe_workQueueCopy(items,\ 100,\ thread->workQueue)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ workQueueObj\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nitems\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ workQueueObj,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ itemToStringObj(items\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"workQueue\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ workQueueObj)\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"isDeactivated\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewIntObj(interp,\ thread->isDeactivated))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"currentItemStartTimestamp\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_ObjPrintf(\"%\"\ PRId64,\ thread->currentItemStartTimestamp))\;\n\n\ \ \ \ \ \ \ \ int64_t\ now\ =\ timestamp_get(thread->clockid)\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"elapsed\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ (double)(now\ -\ thread->currentItemStartTimestamp)\ /\ 1000.0))\;\n\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_allocs\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_allocs))\;\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ ret,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObj(interp,\ \"_frees\",\ -1),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewDoubleObj(interp,\ thread->_frees))\;\n\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ workerInfoFromTid\ \{int\ tid\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ threadCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (threads\[i\].tid\ ==\ tid)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ workerInfo(i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewEmptyStringObj(interp)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ #include\ \"vendor/c11-queues/mpmc_queue.h\"\n\ \ \ \ \ \ \ \ extern\ struct\ mpmc_queue\ globalWorkQueue\;\n\ \ \ \ \ \ \ \ extern\ _Atomic\ int\ globalWorkQueueSize\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ globalWorkQueueAvailable\ \{\}\ size_t\ \{\n\ \ \ \ \ \ \ \ return\ mpmc_queue_available(&globalWorkQueue)\;\n\ \ \ \ \}\n\ \ \ \ #\ Unsafely\ peeks\ at\ the\ queue.\n\ \ \ \ \$cc\ proc\ globalWorkQueueItems\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj\ *ret\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ size_t\ head\ =\ globalWorkQueue.head\;\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ head\;\ i\ <\ globalWorkQueue.tail\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ mpmc_queue_cell\ *cell\ =\ &globalWorkQueue.buffer\[i\ &\ globalWorkQueue.buffer_mask\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ *ptr\ =\ cell->data\;\n\ \ \ \ \ \ \ \ \ \ \ \ WorkQueueItem\ item\ =\ *ptr\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ ret,\ itemToStringObj(item))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nWish\ the\ web\ server\ handles\ route\ \"/threads\"\ with\ handler\ \{\n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n
<unknown> claims builtin-programs/web/web.folk has program code try\ \{\n\nputs\ \"web:\ \[__threadId (
[ m103:0 (s158:0) ]
)<unknown> claims builtin-programs/web/web.folk has program code try\ \{\n\nputs\ \"web:\ \[__threadId\]\ (PID\ \[pid\])\"\n\n#\ We\ need\ to\ handle\ SIGPIPE\ so\ closing\ a\ tab\ doesn't\ crash\ Folk,\ but\n#\ we\ don't\ want\ to\ block/ignore,\ because\ that\ will\ cause\ child\n#\ processes\ to\ also\ block/ignore\ and\ behave\ weirdly.\nsignal\ handle\ SIGPIPE\n\n#\ To\ force\ a\ rebuild:\ rm\ vendor/wslay/Makefile\nif\ \{!\[file\ exists\ vendor/wslay/Makefile\]\}\ \{\n\ \ \ \ puts\ \"web:\ Configuring\ libwslay...\"\n\ \ \ \ exec\ sh\ -c\ \{cd\ vendor/wslay\ &&\ autoreconf\ -i\ &&\ automake\ &&\ autoconf\ &&\ ./configure\}\ \\\n\ \ \ \ \ \ \ \ >@stdout\ 2>@stderr\n\}\nputs\ \"web:\ Building\ libwslay...\"\nexec\ make\ -C\ vendor/wslay\ >@stdout\ 2>@stderr\nputs\ \"web:\ libwslay\ built.\"\n\nsource\ \"lib/ws.tcl\"\n#\ We\ export\ wsLib\ so\ that\ other\ threads\ can\ emit\ messages\ onto\n#\ websockets.\nClaim\ the\ websocket\ library\ is\ \$wsLib\n\nproc\ handleConnect\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ timeout\ 2000\n\ \ \ \ fileevent\ \$chan\ readable\ \[list\ apply\ \{\{chan\ addr\}\ \{\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleRead\ \$chan\ \$addr\n\ \ \ \ \ \ \ \ \}\ on\ signal\ \{sig\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$sig\ on\ \$chan\ \$addr\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$chan\ \$addr\]\n\}\n\nproc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\nproc\ readFile\ \{filename\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\;\ close\ \$fd\;\ return\ \$response\n\}\n\nproc\ headerGet\ \{headers\ name\ args\}\ \{\n\ \ \ \ foreach\ \{k\ v\}\ \$headers\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ -nocase\ \$k\ \$name\]\}\ \{\ return\ \$v\ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[llength\ \$args\]\ >\ 0\}\ \{\ return\ \[lindex\ \$args\ 0\]\ \}\n\ \ \ \ error\ \"missing\ HTTP\ header\ \$name\"\n\}\n\nproc\ handlePage\ \{path\ httpStatusVar\ contentTypeVar\}\ \{\n\ \ \ \ upvar\ \$contentTypeVar\ contentType\n\ \ \ \ switch\ -exact\ --\ \$path\ \{\n\ \ \ \ \ \ \ \ \"/favicon.ico\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"image/x-icon\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/favicon.ico\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/style.css\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/css\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"assets/style.css\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/lib/folk.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"lib/folk.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \"/vendor/idiomorph.js\"\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/javascript\"\n\ \ \ \ \ \ \ \ \ \ \ \ readFile\ \"vendor/idiomorph.js\"\ contentType\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ \$httpStatusVar\ httpStatus\n\ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 404\ Not\ Found\"\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <b>\$path</b>\ Not\ found.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ parseQueryString\ \{queryString\}\ \{\n\ \ \ \ set\ QUERY\ \[dict\ create\]\n\ \ \ \ if\ \{\$queryString\ eq\ \"\"\}\ \{\ return\ \$QUERY\ \}\n\n\ \ \ \ set\ queryString\ \[string\ range\ \$queryString\ 1\ end\]\n\ \ \ \ foreach\ pair\ \[split\ \$queryString\ &\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^=\]*)=(.*)\$\}\ \$pair\ ->\ key\ value\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ URL\ decode\ key\ and\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$key\ \{\ \}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$key\ \{\[format\ %c\ 0x\\1\]\}\ key\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \[subst\ \$key\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{\\+\}\ \$value\ \{\ \}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ regsub\ -all\ \{%(\[0-9A-Fa-f\]\{2\})\}\ \$value\ \{\[format\ %c\ 0x\\1\]\}\ value\n\ \ \ \ \ \ \ \ \ \ \ \ set\ value\ \[subst\ \$value\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ QUERY\ \$key\ \$value\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$QUERY\n\}\n\nfn\ HtmlWhen\ args\ \{\n\ \ \ \ set\ callbacks\ \[dict\ create\]\n\ \ \ \ set\ pattern\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$args\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ arg\ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ if\ \{\$arg\ in\ \[list\ \"-beforeNodeAdded\"\ \"-afterNodeAdded\"\ \"-beforeNodeMorphed\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-afterNodeMorphed\"\ \"-beforeNodeRemoved\"\ \"-afterNodeRemoved\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"-beforeAttributeUpdated\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ callbacks\ \[string\ range\ \$arg\ 1\ end\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$args\ \$i\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pattern\ \$arg\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ body\ \[lindex\ \$pattern\ end\]\n\ \ \ \ set\ pattern\ \[lreplace\ \$pattern\ end\ end\]\n\ \ \ \ set\ envStack\ \[uplevel\ captureEnvStack\]\n\ \ \ \ lappend\ envStack\ \[list\ ^HtmlWhen\ \$\{^HtmlWhen\}\]\n\ \ \ \ #\ TODO:\ Retract\ this\ when\ the\ page\ is\ closed.\n\ \ \ \ When\ -noncapturing\ the\ collected\ results\ for\ \$pattern\ are\ /results/\ \\\n\ \ \ \ \ \ \ \ \[list\ apply\ \{\{pattern\ body\ envStack\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ proc\ htmlEscape\ \{s\}\ \{\ string\ map\ \{&\ \"&\;\"\ <\ \"<\;\"\ >\ \">\;\"\ \"\\\"\"\ \""\;\"\}\ \$s\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ results\ results\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ envStack\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Notify:\ the\ html\ for\ \$pattern\ is\ \[join\ \$htmls\ \\n\]\n\ \ \ \ \ \ \ \ \}\}\ \$pattern\ \$body\ \$envStack\]\n\n\ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ lappend\ envStack\ \{\}\n\ \ \ \ #\ HACK:\ ForEach!\ won't\ work\ on\ collection\ since\ the\ When\ when\ ->\n\ \ \ \ #\ creating\ wish\ doesn't\ exist.\n\ \ \ \ if\ \{\[lrange\ \$pattern\ 0\ 3\]\ eq\ \"the\ collected\ results\ for\"\}\ \{\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ \{*\}\[lindex\ \$pattern\ 4\]\]\n\ \ \ \ \ \ \ \ set\ resultsVar\ \[__scanVariable\ \[lindex\ \$pattern\ 6\]\]\n\ \ \ \ \ \ \ \ lset\ envStack\ end\ \[list\ \$resultsVar\ \$results\]\n\ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ ForEach!\ \{*\}\$pattern\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lset\ envStack\ end\ \$__result\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[applyBlock\ \$body\ \$envStack\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ callbacksJs\ \[join\ \[lmap\ \{callbackName\ callback\}\ \$callbacks\ \{\n\ \ \ \ \ \ \ \ subst\ \{\$callbackName:\ \$callback\}\n\ \ \ \ \}\]\ ,\]\n\ \ \ \ return\ \[subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"display:\ contents\;\">\[join\ \$htmls\ \\n\]</div>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ (function()\ \{\n\ \ \ \ \ \ \ \ \ \ const\ el\ =\ document.currentScript.previousElementSibling\;\n\ \ \ \ \ \ \ \ \ \ const\ callbacks\ =\ \{\$callbacksJs\}\;\n\ \ \ \ \ \ \ \ \ \ folk.subscribe(`the\ html\ for\ \{\$pattern\}\ is\ /html/`,\ (\{html\})\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (window.Idiomorph)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Idiomorph.morph(el,\ html,\ \{morphStyle:'innerHTML',\ callbacks:callbacks\})\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ el.innerHTML\ =\ html\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \})()\;\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \}\]\n\}\n\nproc\ handleRead\ \{chan\ addr\}\ \{\n\ \ \ \ \$chan\ buffering\ none\n\n\ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ set\ firstline\ \$line\n\n\ \ \ \ #\ puts\ \"Http\ (\[clock\ format\ \[clock\ seconds\]\ -format\ \"%H:%M:%S\"\]):\ \$chan\ \$addr:\ \$line\"\n\ \ \ \ set\ headers\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ gets\ \$chan\ line\;\ set\ line\ \[string\ range\ \$line\ 0\ end-1\]\n\ \ \ \ \ \ \ \ if\ \{\$line\ eq\ \"\"\}\ \{\ break\ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ Http:\ (\$line)\"\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{^(\[^\\s:\]+)\\s*:\\s*(.+)\}\ \$line\ ->\ k\ v\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ headers\ \$k\ \$v\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ puts\ stderr\ \"Http:\ Weird\ line:\ \$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{\[regexp\ \{GET\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\ &&\ \$path\ ne\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ set\ response\ \{\}\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ ForEach!\ /someone/\ wishes\ the\ web\ server\ handles\ route\ /route/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ handler\ \[dict\ get\ \$options\ handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[regexp\ -inline\ ^\$\{route\}(\\\\?.*)?\$\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$vars\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ queryString\ \[lindex\ \$vars\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ QUERY\ \[parseQueryString\ \$queryString\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^html\ \[proc\ html\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ text/html\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ^json\ \[proc\ json\ \{body\}\ \{dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\\nConnection:\ close\\nContent-Type:\ application/json\;\ charset=utf-8\\n\\n\"\ body\ \$body\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lindex\ \$handler\ 0\]\ eq\ \"applyBlock\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ create\ QUERY\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$vars\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ \$i\ \[lindex\ \$vars\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lset\ handler\ 2\ \[linsert\ \[lindex\ \$handler\ 2\]\ end\ \$env\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[\{*\}\$handler\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ varNames\ \[lseq\ \[llength\ \$vars\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ varNames\ QUERY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[apply\ \[list\ \$varNames\ \$handler\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$vars\ \$QUERY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$response\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text/html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[handlePage\ \$path\ httpStatus\ contentType\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"\$httpStatus\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$response\ statusAndHeaders\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Response\ not\ generated\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ \{err\ opts\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errorInfo\ \[dict\ get\ \$opts\ -errorinfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ src\ \[lindex\ \$errorInfo\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Web\ error\ in\ \$src\ (\$path):\ \$err\\n\ \ \[errorInfo\ \$err\ \$errorInfo\]\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contentType\ \"text-html\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <title>folk:\ 500\ Internal\ Server\ Error</title>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \$err\]:\n\[htmlEscape\ \[errorInfo\ \$err\ \$errorInfo\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ response\ \[dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 500\ Internal\ Server\ Error\\nConnection:\ close\\nContent-Type:\ \$contentType\\n\\n\"\ body\ \$body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ statusAndHeaders\]\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$response\ body\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[dict\ get\ \$response\ body\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[regexp\ \{POST\ (\[^\ \]*)\ HTTP/1.1\}\ \$firstline\ ->\ path\]\}\ \{\n\ \ \ \ \ \ \ \ set\ httpStatus\ \"HTTP/1.1\ 200\ OK\"\n\ \ \ \ \ \ \ \ set\ contentType\ \"text/plain\;\ charset=utf-8\"\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"\$httpStatus\\r\\nConnection:\ close\\r\\nContent-Type:\ \$contentType\\r\\n\\r\\n\"\n\n\ \ \ \ \ \ \ \ set\ body\ \[\$chan\ read\ \[headerGet\ \$headers\ Content-Length\]\]\n\ \ \ \ \ \ \ \ #\ puts\ \"\ \ (\$body)\"\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \[eval\ \$body\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"Error:\ \$e\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$chan\n\n\ \ \ \ \}\ elseif\ \{\[info\ exists\ path\]\ &&\ \$path\ eq\ \"/ws\"\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"web:\ Request\ for\ /ws\ (\$headers)\"\n\ \ \ \ \ \ \ \ set\ clientKey\ \[headerGet\ \$headers\ Sec-WebSocket-Key\ \"\"\]\n\ \ \ \ \ \ \ \ if\ \{\$clientKey\ eq\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$chan\ \"HTTP/1.1\ 400\ Bad\ Request\\r\\nConnection:\ close\\r\\nContent-Type:\ text/plain\;\ charset=utf-8\\r\\n\\r\\nMissing\ Sec-WebSocket-Key\\r\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$chan\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ WsConnection\ upgrade\ \$chan\ \$clientKey\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ Retract!\ websocket\ \$chan\ is\ connected\]\n\ \ \ \ \ \ \ \ Assert!\ websocket\ \$chan\ is\ connected\n\n\ \ \ \ \}\ else\ \{\ puts\ \"Closing:\ \$chan\ \$addr\ \$headers\"\;\ close\ \$chan\ \}\n\}\n\nwhile\ true\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[socket\ stream.server\ 4273\]\n\ \ \ \ \ \ \ \ \$f\ listen\ 128\n\ \ \ \ \ \ \ \ \$f\ readable\ \[lambda\ \{\}\ \{f\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ client\ \[\$f\ accept\ addr\]\n\ \ \ \ \ \ \ \ \ \ \ \ handleConnect\ \$client\ \$addr\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ break\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ #\ Handles\ failure\ to\ bind\ to\ :4273.\ We\ try\ again\ in\ a\ second.\n\ \ \ \ \ \ \ \ puts\ stderr\ \"web:\ \$e\"\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\nvwait\ forever\n\n\}\ on\ error\ \{e\ opts\}\ \{\n\ \ \ \ puts\ \$::realStderr\ \"WARNING:\ web.folk\ failed\ to\ initialize\;\nthe\ web\ server\ is\ probably\ down\;\ check\ /var/tmp/folk-\[pid\]/\ for\ log\ files.\n(Make\ sure\ libtool\ and\ autoconf-archive\ are\ installed.)\n------------------------------------------\n\[errorInfo\ \$e\]\"\n\ \ \ \ return\ -options\ \$opts\ \$e\n\}\n
<unknown> claims builtin-programs/web/quads.folk has program code {Wish the web server handles route (
[ m104:0 (s162:0) ]
)<unknown> claims builtin-programs/web/quads.folk has program code {Wish the web server handles route "/quads" with handler {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
}
}
<unknown> claims builtin-programs/web/statements.folk has program code {When the db library is /dbLib (
[ m106:0 (s161:0) ]
)<unknown> claims builtin-programs/web/statements.folk has program code {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/statements" with handler {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
}
}
}
<unknown> claims builtin-programs/web/trie-graph.folk has program code set\ trieLib\ \[apply\ \{\{\}\ (
[ m109:0 (s168:0) ]
)<unknown> claims builtin-programs/web/trie-graph.folk has program code set\ trieLib\ \[apply\ \{\{\}\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ cflags\ -I.\ trie.o\n\ \ \ \ \$cc\ include\ <stdlib.h>\n\ \ \ \ \$cc\ include\ <string.h>\n\ \ \ \ \$cc\ include\ \"trie.h\"\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ Db\ Db\;\n\ \ \ \ \ \ \ \ extern\ Db*\ db\;\n\n\ \ \ \ \ \ \ \ extern\ void\ dbLockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ void\ dbUnlockClauseToStatementRef(Db*\ db)\;\n\ \ \ \ \ \ \ \ extern\ Trie*\ dbGetClauseToStatementRef(Db*\ db)\;\n\n#ifdef\ TRACY_ENABLE\n\n#include\ <string.h>\nvoid\ *tmalloc(size_t\ sz)\ \{\n\ \ \ \ void\ *ptr\ =\ malloc(sz)\;\n\ \ \ \ TracyCAllocS(ptr,\ sz,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nvoid\ *tcalloc(size_t\ s1,\ size_t\ s2)\ \{\n\ \ \ \ void\ *ptr\ =\ calloc(s1,\ s2)\;\n\ \ \ \ TracyCAllocS(ptr,\ s1\ *\ s2,\ 4)\;\n\ \ \ \ return\ ptr\;\n\}\nchar\ *tstrdup(const\ char\ *s0)\ \{\n\ \ \ \ int\ sz\ =\ strlen(s0)\ +\ 1\;\n\ \ \ \ char\ *s\ =\ tmalloc(sz)\;\n\ \ \ \ memcpy(s,\ s0,\ sz)\;\n\ \ \ \ return\ s\;\n\}\nvoid\ tfree(void\ *ptr)\ \{\n\ \ \ \ TracyCFreeS(ptr,\ 4)\;\n\ \ \ \ free(ptr)\;\n\}\n\n#else\n\n#define\ tmalloc\ malloc\n#define\ tcalloc\ calloc\n#define\ tstrdup\ strdup\n#define\ tfree\ free\n\n#endif\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ tclify\ \{Trie*\ trie\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ objc\ =\ 3\ +\ trie->branchesCount\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ objv\[objc\]\;\n\ \ \ \ \ \ \ \ objv\[0\]\ =\ Jim_ObjPrintf(\"x%\"\ PRIxPTR,\ (uintptr_t)\ trie)\;\n\ \ \ \ \ \ \ \ objv\[1\]\ =\ trie->key\ ?\ Jim_ObjPrintf(\"%s\",\ trie->key)\ :\ Jim_ObjPrintf(\"ROOT\")\;\n\ \ \ \ \ \ \ \ objv\[2\]\ =\ trie->value\ ?\ Jim_ObjPrintf(\"%\"PRIu64,\ trie->value)\ :\ Jim_ObjPrintf(\"NULL\")\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ trie->branchesCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ HACK:\ const\ isn't\ supported\ yet,\ so\ have\ to\ cast.\n\ \ \ \ \ \ \ \ \ \ \ \ objv\[3+i\]\ =\ trie->branches\[i\]\ ?\ tclify((Trie\ *)trie->branches\[i\])\ :\ Jim_NewStringObj(interp,\ \"\",\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ objv,\ objc)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ dbTrieTclify\ \{\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ dbLockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Trie*\ trie\ =\ dbGetClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ Jim_Obj*\ ret\ =\ tclify(trie)\;\n\ \ \ \ \ \ \ \ dbUnlockClauseToStatementRef(db)\;\n\ \ \ \ \ \ \ \ return\ ret\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ jimObjToClause\ \{Jim_Obj*\ clauseObj\}\ Clause*\ \{\n\ \ \ \ \ \ \ \ int\ nTerms\ =\ Jim_ListLength(interp,\ clauseObj)\;\n\ \ \ \ \ \ \ \ Clause*\ clause\ =\ clauseNew(nTerms)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ termObj\ =\ Jim_ListGetIndex(interp,\ clauseObj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ termLen\;\n\ \ \ \ \ \ \ \ \ \ \ \ const\ char*\ termStr\ =\ Jim_GetString(termObj,\ &termLen)\;\n\ \ \ \ \ \ \ \ \ \ \ \ clause->terms\[i\]\ =\ termNew(termStr,\ termLen)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ clause\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ clauseToJimObj\ \{Clause*\ clause\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ termObjs\[clause->nTerms\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ clause->nTerms\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ termObjs\[i\]\ =\ Jim_NewStringObj(interp,\ termPtr(clause->terms\[i\]),\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ termLen(clause->terms\[i\]))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ termObjs,\ clause->nTerms)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ new\ \{\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieNew()\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ add\ \{Trie*\ trie\ Jim_Obj*\ patternObj\ uint64_t\ value\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ return\ (Trie\ *)trieAdd(trie,\ tmalloc,\ tfree,\ pattern,\ value)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ lookup\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\ =\ trieLookup(trie,\ pattern,\ results,\ 50)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj*\ resultObjs\[resultCount\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ resultCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ resultObjs\[i\]\ =\ Jim_NewIntObj(interp,\ results\[i\])\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ Jim_NewListObj(interp,\ resultObjs,\ resultCount)\;\n\ \ \ \ \}\n\ \ \ \ \$cc\ proc\ remove_\ \{Trie*\ trie\ Jim_Obj*\ patternObj\}\ Trie*\ \{\n\ \ \ \ \ \ \ \ uint64_t\ results\[50\]\;\n\ \ \ \ \ \ \ \ Clause*\ pattern\ =\ jimObjToClause(patternObj)\;\n\ \ \ \ \ \ \ \ int\ resultCount\;\n\ \ \ \ \ \ \ \ trie\ =\ (Trie\ *)trieRemove(trie,\ tmalloc,\ tfree,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pattern,\ results,\ 50,\ &resultCount)\;\n\ \ \ \ \ \ \ \ free(pattern)\;\n\ \ \ \ \ \ \ \ return\ trie\;\n\ \ \ \ \}\n\n\ \ \ \ return\ \[\$cc\ compile\]\n\}\}\]\n\nset\ trieDotify\ \{\{trieLib\ tclifiedTrie\}\ \{\n\ \ \ \ local\ proc\ idify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ generate\ id-able\ word\ by\ eliminating\ all\ non-alphanumeric\n\ \ \ \ \ \ \ \ regsub\ -all\ \{\\W+\}\ \$word\ \"_\"\n\ \ \ \ \}\n\ \ \ \ local\ proc\ labelify\ \{word\}\ \{\n\ \ \ \ \ \ \ \ #\ shorten\ the\ longest\ lines\n\ \ \ \ \ \ \ \ set\ word\ \[join\ \[lmap\ line\ \[split\ \$word\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\ \[string\ length\ \$line\]\ >\ 80\ ?\ \"\[string\ range\ \$line\ 0\ 80\]...\"\ :\ \$line\ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ string\ map\ \{\"\\\"\"\ \"\\\\\\\"\"\}\ \[string\ map\ \{\"\\\\\"\ \"\\\\\\\\\"\}\ \$word\]\n\ \ \ \ \}\n\ \ \ \ local\ proc\ subdot\ \{subtrie\}\ \{\n\ \ \ \ \ \ \ \ set\ branches\ \[lassign\ \$subtrie\ ptr\ key\ id\]\n\n\ \ \ \ \ \ \ \ set\ dot\ \[list\]\n\ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ \\\[label=\\\"\[labelify\ \$key\]\\\"\\\]\;\"\n\ \ \ \ \ \ \ \ foreach\ branch\ \$branches\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$branch\ eq\ \{\}\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ branchptr\ \[lindex\ \$branch\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \"\$ptr\ ->\ \$branchptr\;\"\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dot\ \[subdot\ \$branch\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[join\ \$dot\ \"\\n\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \"digraph\ \{\ rankdir=LR\;\ \[subdot\ \$tclifiedTrie\]\ \}\"\n\}\}\n\nset\ getDotAsPdf\ \{\{dot\}\ \{\n\ \ \ \ set\ fd\ \[open\ |\[list\ dot\ -Tpdf\ <<\$dot\]\ rb\]\n\ \ \ \ set\ response\ \[read\ \$fd\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ return\ \$response\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{exec\ which\ dot\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"graphviz\ not\ installed!\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\}\n\nWish\ the\ web\ server\ handles\ route\ \{/trie-graph\\.pdf\}\ with\ handler\ \{\n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\}\n
<unknown> claims builtin-programs/web/keyboards.folk has program code {Wish the web server handles ro (
[ m110:0 (s167:0) ]
)<unknown> claims builtin-programs/web/keyboards.folk has program code {Wish the web server handles route "/keyboards$" with handler {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
}
}
<unknown> claims builtin-programs/web/page.folk has program code Wish\ the\ web\ server\ handles\ rou (
[ m112:0 (s172:0) ]
)<unknown> claims builtin-programs/web/page.folk has program code Wish\ the\ web\ server\ handles\ route\ \{/page/(.*)\$\}\ with\ handler\ \{\n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n
<unknown> claims builtin-programs/web/new.folk has program code Wish\ the\ web\ server\ handles\ rout (
[ m115:0 (s180:0) ]
)<unknown> claims builtin-programs/web/new.folk has program code Wish\ the\ web\ server\ handles\ route\ \"/new\"\ with\ nav\ \"<button>New\ program</button>\"\ handler\ \{\n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/web/atomicallys.folk has program code {When the db library is /dbLi (
[ m116:0 (s177:0) ]
)<unknown> claims builtin-programs/web/atomicallys.folk has program code {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/atomicallys" with handler {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
}
}
}
<unknown> claims builtin-programs/web/log.folk has program code {Wish the web server handles route {/ (
[ m117:0 (s181:0) ]
)<unknown> claims builtin-programs/web/log.folk has program code {Wish the web server handles route {/log/(.+)$} with hidden true handler {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
}
}
<unknown> claims builtin-programs/web/camera-frame.folk has program code When\ the\ jpeg\ library\ is (
[ m119:0 (s183:0) ]
)<unknown> claims builtin-programs/web/camera-frame.folk has program code When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/camera-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/web/apriltag-frame.folk has program code When\ the\ jpeg\ library\ (
[ m123:0 (s188:0) ]
)<unknown> claims builtin-programs/web/apriltag-frame.folk has program code When\ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\ \ \ \ Wish\ the\ web\ server\ handles\ route\ \{/apriltag-frame\}\ with\ handler\ \{\n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/web/report.folk has program code {When the db library is /dbLib/ {
(
[ m124:0 (s190:0) ]
)<unknown> claims builtin-programs/web/report.folk has program code {When the db library is /dbLib/ {
set db [__db]
Wish the web server handles route "/report" with handler {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
}
}
}
<unknown> claims builtin-programs/web/printed-programs.folk has program code {Wish the web server han (
[ m126:0 (s192:0) ]
)<unknown> claims builtin-programs/web/printed-programs.folk has program code {Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
}
}
<unknown> claims builtin-programs/web/index.folk has program code Wish\ the\ web\ server\ handles\ ro (
[ m129:0 (s197:0) ]
)<unknown> claims builtin-programs/web/index.folk has program code Wish\ the\ web\ server\ handles\ route\ \"/\"\ with\ handler\ \{\n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n\}\n
<unknown> claims builtin-programs/web/camera.folk has program code {Wish the web server handles route (
[ m130:0 (s198:0) ]
)<unknown> claims builtin-programs/web/camera.folk has program code {Wish the web server handles route {/camera} with handler {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
}
}
<unknown> claims builtin-programs/calibrate/calibration-board.folk has program code #\ Goal\ of\ the\ (
[ m133:0 (s202:0) ]
)<unknown> claims builtin-programs/calibrate/calibration-board.folk has program code #\ Goal\ of\ the\ calibration\ board\ is\ to\ have\ the\ user\ do\ four\n#\ measurements:\n#\n#\ -\ paper\ edge\ to\ top\ margin\n#\n#\ -\ paper\ edge\ to\ bottom\ margin\n#\n#\ -\ paper\ edge\ to\ left\ margin\n#\n#\ -\ tag\ inner\ width,\ to\ account\ for\ scaling.\ (We\ also\ want\ this\ tag\n#\ \ \ inner\ width\ to\ be\ exactly\ the\ same\ as\ the\ tag\ inner\ width\ that\ we\n#\ \ \ use\ on\ every\ printed\ program,\ so\ that\ if\ the\ user\ measures\ the\ tag\n#\ \ \ wrong,\ it\ still\ looks\ OK\ on\ the\ average\ program.)\n#\n#\ Then\ we\ can\ correct\ for\ these\ factors\ in\ all\ future\ prints,\ so\ we\n#\ can\ print\ mm-accurate.\n\n#\ These\ values\ are\ all\ in\ points\ (1/72\ of\ an\ inch).\nset\ marginTop\ 48\;\ set\ marginLeft\ 48\n\nset\ measureTop\ \[/\ \$marginTop\ 2\]\;\ set\ measureLeft\ \[/\ \$marginLeft\ 2\]\nset\ tagInnerSideLength\ 70\n\nWhen\ the\ calibration\ measurements\ are\ /measurements/\ \{\n\ \ \ \ set\ m_tag\ \[string\ trimright\ \[dict\ get\ \$measurements\ tagSideLength\]\ mm\]\n\ \ \ \ set\ m_left\ \[string\ trimright\ \[dict\ get\ \$measurements\ left\]\ mm\]\n\ \ \ \ set\ m_bottom\ \[string\ trimright\ \[dict\ get\ \$measurements\ bottom\]\ mm\]\n\n\ \ \ \ #\ Derive\ a\ PostScript\ CTM\ that\ maps\ calibrated\ space\ (origin\ at\n\ \ \ \ #\ paper\ bottom-left,\ 1\ unit\ =\ 1\ physical\ point\ =\ 25.4/72\ mm)\ to\n\ \ \ \ #\ the\ printer's\ raw\ PS\ coordinate\ space.\n\ \ \ \ #\n\ \ \ \ #\ The\ calibration\ board\ was\ printed\ unmediated,\ so\ its\ PS\ coords\n\ \ \ \ #\ are\ the\ printer's\ raw\ coords.\ \ The\ measurement\ lines\ were\ drawn\n\ \ \ \ #\ at\ PS\ positions\ measureLeft\ and\ measureTop\;\ the\ tag\ inner\ side\n\ \ \ \ #\ was\ tagInnerSideLength\ PS\ points.\ \ From\ the\ physical\ measurements\n\ \ \ \ #\ (in\ mm)\ we\ can\ recover\ the\ printer's\ scale\ and\ origin\ offset.\n\ \ \ \ set\ scale\ \[expr\ \{25.4\ *\ \$tagInnerSideLength\ /\ (72.0\ *\ \$m_tag)\}\]\n\ \ \ \ set\ tx\ \[expr\ \{\$measureLeft\ -\ \$m_left\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\ \ \ \ set\ ty\ \[expr\ \{\$measureTop\ -\ \$m_bottom\ *\ \$tagInnerSideLength\ /\ \$m_tag\}\]\n\n\ \ \ \ Claim\ the\ calibrated\ print\ scale\ is\ \$scale\n\ \ \ \ Claim\ the\ calibrated\ print\ translation\ is\ \[list\ \$tx\ \$ty\]\n\}\n\nWhen\ the\ print\ library\ is\ /printLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ \{\n\nfn\ makeCalibrationBoardPs\ \{\}\ \{\n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n\}\nClaim\ the\ makeCalibrationBoardPs\ is\ \[fn\ makeCalibrationBoardPs\]\n\nfn\ makeCalibrationBoardPdf\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ fp\ \[open\ \[list\ |ps2pdf\ -\ -\ <<\$ps\]\ rb\]\n\ \ \ \ set\ pdf\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$pdf\n\}\nClaim\ the\ makeCalibrationBoardPdf\ is\ \[fn\ makeCalibrationBoardPdf\]\n\nfn\ makeCalibrationBoardPng\ \{\}\ \{\n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n\}\nClaim\ the\ makeCalibrationBoardPng\ is\ \[fn\ makeCalibrationBoardPng\]\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.pdf\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibrate/board.png\}\ with\ hidden\ true\ handler\ \{\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n\}\n\n\}\n
<unknown> claims builtin-programs/calibrate/calibrate-page.folk has program code When\ the\ codeToPos (
[ m135:0 (s208:0) ]
)<unknown> claims builtin-programs/calibrate/calibrate-page.folk has program code When\ the\ codeToPostScript\ is\ /codeToPostScript/\ \{\n\nfn\ codeToPostScript\n\nWish\ the\ web\ server\ handles\ route\ \"/calibrate\"\ with\ hidden\ true\ handler\ \{\n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n\}\n\nWhen\ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ \{\n\ \ \ \ #\ Hold\ reporting\ info\ for\ the\ Web\ page.\n\ \ \ \ set\ posesReport\ \[subst\ \{\n\ \ \ \ \ \ <p>Poses:</p><ol>\n\ \ \ \ \ \ \[join\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$pose\ cameraWidth\]\n\ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$pose\ cameraHeight\]\n\ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <li\ style=\"padding-bottom:\ 1em\">\n\ \ \ \ \ \ \ \ \ \ RMSE\ \[dict\ getdef\ \$pose\ rmse\ (unavailable)\]\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\">\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ src=\"/calibration-poses/\[dict\ get\ \$pose\ imageName\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ style=\"position:\ absolute\;\ top:\ 0\;\ left:\ 0\;\ width:\ 300px\;\ height:\ \[expr\ \{(300.0\ /\ \$width)\ *\ \$height\}\]px\;\ pointer-events:\ none\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \[dict\ get\ \$pose\ cameraWidth\]\ \[dict\ get\ \$pose\ cameraHeight\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ det\ \[dict\ values\ \[dict\ get\ \$pose\ tags\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \[string\ repeat\ \{<li>Not\ detected\ yet</li>\}\ \[-\ 10\ \[llength\ \$calibrationPoses\]\]\]\n\ \ \ \ \ \ </ol>\n\ \ \ \ \}\]\n\n\ \ \ \ When\ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$posesReport\n\ \ \ \ \}\n\ \ \ \ When\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ \ \ \ \ set\ calibrationReport\ \"\$posesReport\n\ \ \ \ \ \ \ \ <p>Calibration:</p><pre>\nCamera\ intrinsics\ --------\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ camera\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nCamera\ RMSE\ \[dict\ getdef\ \$calibration\ camera\ rmse\ (unavailable)\]\n\nProjector\ intrinsics\ -----\n\[join\ \[lmap\ \{k\ v\}\ \[dict\ get\ \$calibration\ projector\ intrinsics\]\ \{list\ \$k\ \$v\}\]\ \\n\]\n\nProjector\ RMSE\ \[dict\ getdef\ \$calibration\ projector\ rmse\ (unavailable)\]\n\n----\nStereo\ RMSE\ \[dict\ getdef\ \$calibration\ rmse\ (unavailable)\]\n</pre>\"\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ report\ is\ \$calibrationReport\n\ \ \ \ \}\n\}\n\nWish\ the\ web\ server\ handles\ route\ \{/calibration-poses/(\[^/\]+)\$\}\ with\ handler\ \{\n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n\}\n\n\}\n
<unknown> claims builtin-programs/calibrate/load-calibration.folk has program code When\ display\ /di (
[ m136:0 (s206:0) ]
)<unknown> claims builtin-programs/calibrate/load-calibration.folk has program code When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ set\ warning\ \"WARNING:\ Folk\ hasn't\ been\ calibrated!\nUsing\ default\ (bad)\ calibration.\"\n\n\ \ \ \ puts\ stderr\ \"calibrate:\ \$warning\"\n\ \ \ \ set\ cx\ \[/\ \$displayWidth\ 2.0\]\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.1\]\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\ \ \ \ Wish\ to\ draw\ text\ onto\ \$disp\ with\ \\\n\ \ \ \ \ \ \ \ x\ \$cx\ y\ \[*\ \$displayHeight\ 0.7\]\ radians\ 3.14159\ \\\n\ \ \ \ \ \ \ \ text\ \$warning\ color\ red\ scale\ 40\n\}\n\nWhen\ /nobody/\ claims\ a\ calibration\ from\ camera\ /cam/\ to\ display\ /disp/\ is\ /anything/\ \{\n\ \ \ \ #\ Fallback:\ if\ uncalibrated\ (_no\ calibrations\ at\ all_\ are\ stored),\n\ \ \ \ #\ create\ fake\ intrinsics\ and\ extrinsics.\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ display\ \$disp\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$displayWidth\ height\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$displayWidth\ fy\ \$displayWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$displayWidth\ 2.0\]\ cy\ \[/\ \$displayHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ /cam/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ has\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$cameraWidth\ height\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ fx\ \$cameraWidth\ fy\ \$cameraWidth\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ cx\ \[/\ \$cameraWidth\ 2.0\]\ cy\ \[/\ \$cameraHeight\ 2.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ s\ 0\ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ \}\n\ \ \ \ When\ display\ /disp/\ has\ width\ /any/\ height\ /any/\ &\\\n\ \ \ \ \ \ \ \ \ camera\ /cam/\ has\ width\ /any/\ height\ /any/\ \{\n\ \ \ \ \ \ \ \ Claim\ camera\ \$cam\ to\ display\ \$disp\ has\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ R\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ t\ \{0\ 0\ 0\}\]\n\ \ \ \ \}\n\}\n\nWhen\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /calibration/\ \{\n\ \ \ \ puts\ \"\\n\\n====NEW\ CALIBRATION\ (\[string\ range\ \$calibration\ 0\ 100\])=====\\n\\n\"\n\n\ \ \ \ #\ Backfill\ p1/p2\ for\ calibrations\ saved\ before\ tangential\n\ \ \ \ #\ distortion\ support\ was\ added.\n\ \ \ \ foreach\ device\ \{camera\ projector\}\ \{\n\ \ \ \ \ \ \ \ foreach\ key\ \{p1\ p2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$calibration\ \$device\ intrinsics\ \$key\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ calibration\ \$device\ intrinsics\ \$key\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Claim\ camera\ \$camera\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ Claim\ display\ \$display\ has\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\n\ \ \ \ set\ extrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$calibration\ R_cameraToProjector\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ Claim\ camera\ \$camera\ to\ display\ \$display\ has\ extrinsics\ \$extrinsics\n\}\n\nWhen\ the\ collected\ results\ for\ \{/somebody/\ claims\ the\ default\ program\ geometry\ is\ /geom/\}\ are\ /results/\ \{\n\ \ \ \ set\ defaultGeometry\ \{tagSize\ 30mm\ top\ 28mm\ right\ 28mm\ left\ 157mm\ bottom\ 80mm\}\n\ \ \ \ set\ shouldClaim\ false\n\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\ ||\n\ \ \ \ \ \ \ \ \[llength\ \$results\]\ ==\ 1\ &&\ \[dict\ get\ \[lindex\ \$results\ 0\]\ geom\]\ ==\ \$defaultGeometry\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeometry\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/calibrate/refine.folk has program code #\ refine.folk\ --\n#\n#\ \ (
[ m139:0 (s216:0) ]
)<unknown> claims builtin-programs/calibrate/refine.folk has program code #\ refine.folk\ --\n#\n#\ \ \ \ \ Implements\ nonlinear\ refinement\ of\ camera\ calibration\ (or\n#\ \ \ \ \ projector\ calibration,\ equivalently)\ (see\ Zhengyou\ Zhang)\ using\n#\ \ \ \ \ cmpfit.\n#\n\nWhen\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ From\ https://courses.cs.duke.edu/cps274/fall13/notes/rodrigues.pdf:\nfn\ rotationMatrixToRotationVector\ \{R\}\ \{\n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n\}\n\nfn\ rotationVectorToRotationMatrix\ \{r\}\ \{\n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n\}\n\nset\ NUM_TAGS_IN_MODEL\ 20\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor/cmpfit\ -Wall\ -Werror\nconfigCcWithLibapriltag\ \$cc\n\n\$cc\ include\ <math.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ include\ <apriltag_pose.h>\n\$cc\ include\ <common/matd.h>\n\n#\ Mono\ calibration\n#\ ----------------\n\n\$cc\ code\ \[csubst\ \{\n\ \ \ \ #define\ MAX_POINTS_PER_POSE\ \$\[*\ \$NUM_TAGS_IN_MODEL\ 4\]\n\n\ \ \ \ typedef\ struct\ Intrinsics\ \{\n\ \ \ \ \ \ \ \ double\ fx\;\n\ \ \ \ \ \ \ \ double\ cx\;\n\ \ \ \ \ \ \ \ double\ fy\;\n\ \ \ \ \ \ \ \ double\ cy\;\n\ \ \ \ \ \ \ \ double\ k1\;\n\ \ \ \ \ \ \ \ double\ k2\;\n\ \ \ \ \ \ \ \ double\ p1\;\n\ \ \ \ \ \ \ \ double\ p2\;\n\n\ \ \ \ \ \ \ \ //\ Makes\ it\ easy\ to\ project.\ Same\ information\ as\ fx,\n\ \ \ \ \ \ \ \ //\ cx,\ fy,\ cy.\n\ \ \ \ \ \ \ \ double\ mat\[3\]\[3\]\;\n\ \ \ \ \}\ Intrinsics\;\n\ \ \ \ //\ Load\ intrinsics\ from\ the\ parameter\ list.\n\ \ \ \ int\ loadIntrinsics(Intrinsics*\ intr,\ double*\ x)\ \{\n\ \ \ \ \ \ \ \ int\ k\ =\ 0\;\n\ \ \ \ \ \ \ \ intr->fx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cx\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->fy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->cy\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ double\ intrMatTmp\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{intr->fx,\ \ \ \ \ \ \ \ \ 0,\ \ intr->cx\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ intr->fy,\ \ intr->cy\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{\ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 0,\ \ \ \ \ \ \ \ \ 1\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(intr->mat,\ intrMatTmp,\ sizeof(intr->mat))\;\n\n\ \ \ \ \ \ \ \ intr->k1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->k2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p1\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ intr->p2\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ return\ k\;\n\ \ \ \ \}\n\n\ \ \ \ int\ MonoPoseCount\;\n\ \ \ \ int\ MonoPointsCount\;\n\ \ \ \ int*\ MonoPosePointsCount\;\n\ \ \ \ double\ (*MonoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*MonoPosePoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\}\]\n\$cc\ proc\ monoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ posePoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(MonoPosePointsCount)\;\n\ \ \ \ free(MonoPoseModelPoints)\;\n\ \ \ \ free(MonoPosePoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ MonoPoseCount\ =\ poseCount\;\n\ \ \ \ MonoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ MonoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ MonoPosePoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ MonoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ MonoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ MonoPointsCount\ +=\ MonoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ MonoPosePoints\[poseIdx\]\[i\]\[j\]\ =\ posePoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$cc\ code\ \{\n\ \ \ \ void\ rotationVectorToRotationMatrix(double\ r\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ double\ theta\ =\ sqrt(r\[0\]*r\[0\]\ +\ r\[1\]*r\[1\]\ +\ r\[2\]*r\[2\])\;\n\ \ \ \ \ \ \ \ if\ (fabs(theta)\ <\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{1,\ 0,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 1,\ 0\},\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{0,\ 0,\ 1\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ double\ u\[3\]\ =\ \{r\[0\]/theta,\ r\[1\]/theta,\ r\[2\]/theta\}\;\n\ \ \ \ \ \ \ \ double\ ret\[3\]\[3\]\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{cos(theta)\ +\ u\[0\]*u\[0\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[1\]*(1\ -\ cos(theta))\ -\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[0\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[1\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[1\]*(1\ -\ cos(theta))\ +\ u\[2\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[1\]*u\[1\]*(1\ -\ cos(theta)),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[0\]*sin(theta)\},\n\ \ \ \ \ \ \ \ \ \ \ \ \{u\[0\]*u\[2\]*(1\ -\ cos(theta))\ -\ u\[1\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ u\[1\]*u\[2\]*(1\ -\ cos(theta))\ +\ u\[0\]*sin(theta),\n\ \ \ \ \ \ \ \ \ \ \ \ \ cos(theta)\ +\ u\[2\]*u\[2\]*(1\ -\ cos(theta))\}\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ memcpy(out,\ ret,\ sizeof(ret))\;\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Mat3(double\ A\[3\]\[3\],\ double\ B\[3\]\[3\],\ double\ out\[3\]\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 9)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ k\ =\ 0\;\ k\ <\ 3\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\[x\]\ +=\ A\[y\]\[k\]\ *\ B\[k\]\[x\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ mulMat3Vec3(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ memset(out,\ 0,\ sizeof(double)\ *\ 3)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ out\[y\]\ =\ A\[y\]\[0\]*x\[0\]\ +\ A\[y\]\[1\]*x\[1\]\ +\ A\[y\]\[2\]*x\[2\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ void\ project(double\ A\[3\]\[3\],\ double\ x\[3\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ outAug\[3\]\;\ mulMat3Vec3(A,\ x,\ outAug)\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ outAug\[0\]/outAug\[2\]\;\ out\[1\]\ =\ outAug\[1\]/outAug\[2\]\;\n\ \ \ \ \}\n\n\ \ \ \ void\ transformVec3(double\ R\[3\]\[3\],\ double\ t\[3\],\ double\ x\[3\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ out\[3\])\ \{\n\ \ \ \ \ \ \ \ mulMat3Vec3(R,\ x,\ out)\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\ out\[i\]\ +=\ t\[i\]\;\ \}\n\ \ \ \ \}\n\ \ \ \ void\ undistort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x0\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y0\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ x\ =\ x0,\ y\ =\ y0\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 5\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ radial\ =\ 1.0\ +\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ \ \ \ \ x\ =\ (x0\ -\ dx)\ /\ radial\;\n\ \ \ \ \ \ \ \ \ \ \ \ y\ =\ (y0\ -\ dy)\ /\ radial\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ out\[0\]\ =\ x*intr.fx\ +\ intr.cx\;\ out\[1\]\ =\ y*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\ \ \ \ void\ distort(Intrinsics\ intr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ xy\[2\],\ double\ out\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ x\ =\ (xy\[0\]\ -\ intr.cx)/intr.fx\;\n\ \ \ \ \ \ \ \ double\ y\ =\ (xy\[1\]\ -\ intr.cy)/intr.fy\;\n\ \ \ \ \ \ \ \ double\ r2\ =\ x*x\ +\ y*y\;\n\ \ \ \ \ \ \ \ double\ radial\ =\ intr.k1\ *\ r2\ +\ intr.k2\ *\ r2*r2\;\n\ \ \ \ \ \ \ \ double\ dx\ =\ 2*intr.p1*x*y\ +\ intr.p2*(r2\ +\ 2*x*x)\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ intr.p1*(r2\ +\ 2*y*y)\ +\ 2*intr.p2*x*y\;\n\ \ \ \ \ \ \ \ out\[0\]\ =\ (x\ *\ (1.0\ +\ radial)\ +\ dx)*intr.fx\ +\ intr.cx\;\n\ \ \ \ \ \ \ \ out\[1\]\ =\ (y\ *\ (1.0\ +\ radial)\ +\ dy)*intr.fy\ +\ intr.cy\;\n\ \ \ \ \}\n\n\ \ \ \ double\ dist(double\ a\[2\],\ double\ b\[2\])\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ a\[0\]\ -\ b\[0\]\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ a\[1\]\ -\ b\[1\]\;\n\ \ \ \ \ \ \ \ return\ dx*dx\ +\ dy*dy\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ monoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Intrinsics:\n\ \ \ \ Intrinsics\ intr\;\n\ \ \ \ k\ +=\ loadIntrinsics(&intr,\ &x\[k\])\;\n\n\ \ \ \ //\ Extrinsics:\n\ \ \ \ double\ r_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ double\ t_pose\[MonoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ r_pose\[i\]\[0\]\ =\ x\[k++\]\;\ r_pose\[i\]\[1\]\ =\ x\[k++\]\;\ r_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ t_pose\[i\]\[0\]\ =\ x\[k++\]\;\ t_pose\[i\]\[1\]\ =\ x\[k++\]\;\ t_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ assert(k\ ==\ n)\;\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ MonoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Pose\ extrinsics:\n\ \ \ \ \ \ \ \ double\ t\[3\]\;\ memcpy(t,\ t_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ R\[3\]\[3\]\;\ rotationVectorToRotationMatrix(r_pose\[poseIdx\],\ R)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ MonoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &MonoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R,\ t,\ modelPoint,\ idealPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Use\ intrinsics\ to\ project\ down\ to\ ideal\ 2D\n\ \ \ \ \ \ \ \ \ \ \ \ //\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealPlanePoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(intr.mat,\ idealPoint,\ idealPlanePoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ planePoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(intr,\ idealPlanePoint,\ planePoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Add\ an\ error\ term\ to\ fvec.\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(planePoint,\ MonoPosePoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ monoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[MonoPointsCount\]\;\n\ \ \ \ monoFunc(MonoPointsCount,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ MonoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ MonoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ monoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ setvbuf(stdout,\ NULL,\ _IONBF,\ BUFSIZ)\;\n\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 8\ +\ MonoPoseCount*6)\;\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(monoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ MonoPointsCount,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ monoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Stereo\ calibration\n#\ ------------------\n\n\$cc\ code\ \{\n\ \ \ \ int\ StereoPoseCount\;\n\ \ \ \ int\ StereoPointsCount\;\n\ \ \ \ int*\ StereoPosePointsCount\;\n\ \ \ \ double\ (*StereoPoseModelPoints)\[MAX_POINTS_PER_POSE\]\[3\]\;\n\ \ \ \ double\ (*StereoPoseCameraPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\ \ \ \ double\ (*StereoPoseProjectorPoints)\[MAX_POINTS_PER_POSE\]\[2\]\;\n\n\ \ \ \ Intrinsics\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ StereoProjectorIntrinsics\;\n\}\n\$cc\ proc\ stereoSetPoints\ \{int\ poseCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\[\]\ posePointsCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseModelPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseCameraPoints\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ poseProjectorPoints\}\ void\ \{\n\ \ \ \ //\ Free\ previously\ allocated\ memory\n\ \ \ \ free(StereoPosePointsCount)\;\n\ \ \ \ free(StereoPoseModelPoints)\;\n\ \ \ \ free(StereoPoseCameraPoints)\;\n\ \ \ \ free(StereoPoseProjectorPoints)\;\n\n\ \ \ \ //\ Allocate\ new\ arrays\ based\ on\ poseCount\n\ \ \ \ StereoPoseCount\ =\ poseCount\;\n\ \ \ \ StereoPosePointsCount\ =\ malloc(poseCount\ *\ sizeof(int))\;\n\ \ \ \ StereoPoseModelPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[3\]))\;\n\ \ \ \ StereoPoseCameraPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\ \ \ \ StereoPoseProjectorPoints\ =\ malloc(poseCount\ *\ sizeof(double\[MAX_POINTS_PER_POSE\]\[2\]))\;\n\n\ \ \ \ int\ mi\ =\ 0\;\ int\ ci\ =\ 0\;\ int\ pi\ =\ 0\;\n\ \ \ \ StereoPointsCount\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ StereoPosePointsCount\[poseIdx\]\ =\ posePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ StereoPointsCount\ +=\ StereoPosePointsCount\[poseIdx\]\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPosePointsCount\[poseIdx\]\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseModelPoints\[poseIdx\]\[i\]\[j\]\ =\ poseModelPoints\[mi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[i\]\[j\]\ =\ poseCameraPoints\[ci++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 2\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[i\]\[j\]\ =\ poseProjectorPoints\[pi++\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\$cc\ proc\ stereoSetIntrinsics\ \{double\[\]\ cameraIntrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\[\]\ projectorIntrinsics\}\ void\ \{\n\ \ \ \ loadIntrinsics(&StereoCameraIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraIntrinsics)\;\n\ \ \ \ loadIntrinsics(&StereoProjectorIntrinsics,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projectorIntrinsics)\;\n\}\n\$cc\ proc\ stereoFunc\ \{int\ m\ int\ n\ double*\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double*\ fvec\ double**\ dvec\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void*\ _\}\ int\ \{\n\ \ \ \ //\ Intrinsics\ (these\ are\ fixed):\n\ \ \ \ Intrinsics\ camIntr\ =\ StereoCameraIntrinsics\;\n\ \ \ \ Intrinsics\ projIntr\ =\ StereoProjectorIntrinsics\;\n\n\ \ \ \ //\ Unwrap\ the\ parameters\ x\[\]:\n\ \ \ \ int\ k\ =\ 0\;\n\n\ \ \ \ //\ Global\ camera->projector\ extrinsics:\n\ \ \ \ double\ r_cp\[3\]\;\n\ \ \ \ double\ t_cp\[3\]\;\n\ \ \ \ r_cp\[0\]\ =\ x\[k++\]\;\ r_cp\[1\]\ =\ x\[k++\]\;\ r_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ t_cp\[0\]\ =\ x\[k++\]\;\ t_cp\[1\]\ =\ x\[k++\]\;\ t_cp\[2\]\ =\ x\[k++\]\;\n\ \ \ \ double\ R_cp\[3\]\[3\]\;\n\ \ \ \ rotationVectorToRotationMatrix(r_cp,\ R_cp)\;\n\n\ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ double\ rc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ double\ tc_pose\[StereoPoseCount\]\[3\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPoseCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ rc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ rc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \ \ \ \ tc_pose\[i\]\[0\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[1\]\ =\ x\[k++\]\;\ tc_pose\[i\]\[2\]\ =\ x\[k++\]\;\n\ \ \ \ \}\n\n\ \ \ \ int\ f\ =\ 0\;\n\ \ \ \ for\ (int\ poseIdx\ =\ 0\;\ poseIdx\ <\ StereoPoseCount\;\ poseIdx++)\ \{\n\ \ \ \ \ \ \ \ //\ Per-pose\ model->camera\ extrinsics:\n\ \ \ \ \ \ \ \ double\ tc\[3\]\;\ memcpy(tc,\ tc_pose\[poseIdx\],\ sizeof(double\[3\]))\;\n\ \ \ \ \ \ \ \ double\ Rc\[3\]\[3\]\;\ rotationVectorToRotationMatrix(rc_pose\[poseIdx\],\ Rc)\;\n\n\ \ \ \ \ \ \ \ //\ For\ each\ point\ in\ the\ pose:\n\ \ \ \ \ \ \ \ for\ (int\ pointIdx\ =\ 0\;\ pointIdx\ <\ StereoPosePointsCount\[poseIdx\]\;\ pointIdx++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Get\ the\ 3D\ position\ of\ the\ model\ point\ in\ ideal\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera-space\ using\ model\ &\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double*\ modelPoint\ =\ (double*)\ &StereoPoseModelPoints\[poseIdx\]\[pointIdx\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(Rc,\ tc,\ modelPoint,\ idealCameraPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ camera\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealCameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(camIntr.mat,\ idealCameraPoint,\ idealCameraPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ cameraPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(camIntr,\ idealCameraPixelPoint,\ cameraPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(cameraPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseCameraPoints\[poseIdx\]\[pointIdx\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Transform\ the\ point\ from\ ideal\ camera-space\ to\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ideal\ projector-space\ using\ the\ extrinsics.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPoint\[3\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ transformVec3(R_cp,\ t_cp,\ idealCameraPoint,\ idealProjectorPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Project\ the\ point\ down\ from\ ideal\ projector-space\n\ \ \ \ \ \ \ \ \ \ \ \ //\ to\ projector\ pixel\ space.\ Compare\ with\ known\ position.\n\ \ \ \ \ \ \ \ \ \ \ \ double\ idealProjectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ project(projIntr.mat,\ idealProjectorPoint,\ idealProjectorPixelPoint)\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ projectorPixelPoint\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ distort(projIntr,\ idealProjectorPixelPoint,\ projectorPixelPoint)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fvec\[f++\]\ =\ dist(projectorPixelPoint,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StereoPoseProjectorPoints\[poseIdx\]\[pointIdx\])\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ 0\;\n\}\n\$cc\ proc\ stereoComputeError\ \{double\[paramsCount\]\ params\}\ double\ \{\n\ \ \ \ double\ fvec\[StereoPointsCount\ *\ 2\]\;\n\ \ \ \ stereoFunc(StereoPointsCount\ *\ 2,\ paramsCount,\ params,\ fvec,\ NULL,\ NULL)\;\n\ \ \ \ double\ totalError\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ StereoPointsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ /*\ printf(\"\ \ Error\ %d:\ %f\\n\",\ i,\ fvec\[i\])\;\ */\n\ \ \ \ \ \ \ \ totalError\ +=\ fvec\[i\]\;\n\ \ \ \ \}\n\ \ \ \ printf(\"Total\ Error:\ %f\\n\",\ totalError)\;\n\ \ \ \ double\ rmse\ =\ sqrt(totalError\ /\ StereoPointsCount)\;\n\ \ \ \ printf(\"RMSE:\ %f\\n\",\ rmse)\;\n\ \ \ \ return\ rmse\;\n\}\n\$cc\ proc\ stereoRefineCalibrationOptimize\ \{double\[paramsCount\]\ params\}\ Jim_Obj*\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\n\ \ \ \ FOLK_ENSURE(paramsCount\ ==\ 6\ +\ StereoPoseCount*6)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(!isnan(params\[i\]))\;\n\ \ \ \ \}\n\n\ \ \ \ printf(\"Unrefined\ -----------------\\n\")\;\n\ \ \ \ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ mpfit(stereoFunc,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ example\ point\ pairs:\n\ \ \ \ \ \ \ \ \ \ StereoPointsCount\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ paramsCount,\n\ \ \ \ \ \ \ \ \ \ params,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\ NULL,\ &result)\;\n\ \ \ \ printf(\"Refined\ -------------------\\n\")\;\n\ \ \ \ double\ rmse\ =\ stereoComputeError(paramsCount,\ params)\;\n\n\ \ \ \ Jim_Obj*\ paramObjs\[1\ +\ paramsCount\]\;\n\ \ \ \ paramObjs\[0\]\ =\ Jim_NewDoubleObj(interp,\ rmse)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ paramsCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ paramObjs\[1\ +\ i\]\ =\ Jim_NewDoubleObj(interp,\ params\[i\])\;\n\ \ \ \ \}\n\ \ \ \ return\ Jim_NewListObj(interp,\ paramObjs,\ 1\ +\ paramsCount)\;\n\}\n\n#\ Folk\ level\n#\ ----------\n\nset\ refineLib\ \[\$cc\ compile\]\ \;#\ takes\ about\ a\ half-second\n\n#\ Refines\ the\ calibration\ of\ an\ individual\ camera\ or\n#\ projector.\ Takes\ a\ dict\ with\ intrinsics\ (dict\ of\ fx,\ s,\ cx,\ etc)\n#\ and\ poses\ (list\ of\ pose\ dicts).\ Each\ pose\ dict\ should\ have\n#\ modelPoints\ (list\ of\ 3D\ points)\ and\ points\ (list\ of\ 2D\ points)\n#\ and\ R\ and\ t.\ Returns\ dict\ with\ updated\ intrinsics\ and\ poses.\nfn\ refineMonoCalibration\ \{calibration\}\ \{\n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n\}\n\nfn\ refineCalibration\ \{modelLib\ matLib\ setCameraToProjectorExtrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationPoses\ calibration\}\ \{\n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n\}\nClaim\ the\ calibration\ refiner\ is\ \[fn\ refineCalibration\]\n\n\}\n
<unknown> claims builtin-programs/calibrate/model.folk has program code #\ model.folk\ --\n#\n#\ \ \ (
[ m140:0 (s213:0) ]
)<unknown> claims builtin-programs/calibrate/model.folk has program code #\ model.folk\ --\n#\n#\ \ \ \ \ Defines\ datatype\ and\ operations\ for\ calibration\ model.\n\nClaim\ the\ calibration\ model\ library\ is\ \[library\ create\ modelLib\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\n\n\ \ \ \ variable\ ROWS\ 5\n\ \ \ \ variable\ COLS\ 4\n\ \ \ \ proc\ rows\ \{\}\ \{\ variable\ ROWS\;\ return\ \$ROWS\ \}\n\ \ \ \ proc\ cols\ \{\}\ \{\ variable\ COLS\;\ return\ \$COLS\ \}\n\ \ \ \ #\ A\ model\ is\ a\ dictionary\ whose\ keys\ are\ tag\ IDs\ and\ where\ each\n\ \ \ \ #\ value\ is\ a\ dictionary\ with\ keys\ `c`\ and\ `p`\ which\ are\ model\n\ \ \ \ #\ points\ (x,\ y).\n\ \ \ \ proc\ unitModel\ \{\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ set\ UNIT_MODEL\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ \ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ \ \ \ \ set\ pad\ \[expr\ \{\$tagSideLength\ /\ 3\}\]\n\ \ \ \ \ \ \ \ for\ \{set\ row\ 0\}\ \{\$row\ <\ \$ROWS\}\ \{incr\ row\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ col\ 0\}\ \{\$col\ <\ \$COLS\}\ \{incr\ col\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[expr\ \{48600\ +\ \$row*\$COLS\ +\ \$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$col\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{(\$tagOuterLength\ +\ \$pad)*\$row\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ outer\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelX\ \[expr\ \{\$modelX\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelY\ \[expr\ \{\$modelY\ +\ (\$tagOuterLength\ -\ \$tagSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Now\ modelX\ and\ modelY\ are\ the\ top-left\ inner\ corner\ of\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ tag.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopLeft\ \[list\ \$modelX\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTopRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \$modelY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomRight\ \[list\ \[+\ \$modelX\ \$tagSideLength\]\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[list\ \$modelX\ \[+\ \$modelY\ \$tagSideLength\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ c\ \[scale\ 0.5\ \[add\ \$modelTopLeft\ \$modelBottomRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p\ \[list\ \$modelBottomLeft\ \$modelBottomRight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelTopRight\ \$modelTopLeft\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ UNIT_MODEL\ \$id\ \$modelTag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$UNIT_MODEL\n\ \ \ \ \}\n\ \ \ \ #\ Tags\ with\ isPrintedTag\ will\ get\ projected\ to\ PostScript\ points\n\ \ \ \ #\ and\ printed\;\ tags\ with\ isProjectedTag\ will\ get\ projected\ to\n\ \ \ \ #\ Vulkan\ points\ and\ rendered\ on\ projector.\n\n\ \ \ \ #\ Tag\ operations.\n\ \ \ \ #\ ---------------\n\n\ \ \ \ proc\ isCalibrationTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ ROWS\;\ variable\ COLS\n\ \ \ \ \ \ \ \ return\ \$(\$id\ >=\ 48600\ &&\ \$id\ <\ 48600\ +\ \$ROWS*\$COLS)\n\ \ \ \ \}\n\ \ \ \ proc\ isPrintedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ variable\ COLS\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{int(\$idx\ /\ \$COLS)\}\]\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$idx\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$row\ %\ 2\ ==\ 0\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 1)\ :\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$col\ %\ 2\ ==\ 0)\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\ \ \ \ proc\ isProjectedTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isCalibrationTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{!\[isPrintedTag\ \$id\]\}\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ isVersionTag\ \{id\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$id\]\}\ \{\ return\ false\ \}\n\ \ \ \ \ \ \ \ set\ idx\ \[-\ \$id\ 48600\]\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$idx\ %\ 4\ ==\ 1\}\]\ \;#\ for\ checkerboard\n\ \ \ \ \}\n\n\ \ \ \ #\ Model\ operations.\n\ \ \ \ #\ -----------------\n\n\ \ \ \ #\ Takes\ a\ model\ object\ (dictionary\ of\ tag\ ID\ =>\ \{p,\ c\})\ and\n\ \ \ \ #\ rotates\ version\ tags\ according\ to\ version.\n\ \ \ \ proc\ updateModelVersion\ \{model\ version\}\ \{\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ version\ tag.\ Rotate\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$model\ \$id\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rotatedCorners\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 4\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ rotatedCorners\ \[lindex\ \$p\ \[expr\ \{(\$i\ +\ \$version)\ %\ 4\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ model\ \$id\ p\ \$rotatedCorners\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$model\n\ \ \ \ \}\n\ \ \ \ proc\ scaleModel\ \{model\ scale\}\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ c\ \[scale\ \$scale\ \[dict\ get\ \$tag\ c\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ ret\ \$id\ p\ \[scale\ \$scale\ \[dict\ get\ \$tag\ p\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ proc\ countProjectedTags\ \{model\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\}\ \{\ incr\ i\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$i\n\ \ \ \ \}\n\n\ \ \ \ #\ Detected\ tag-list\ operations.\n\ \ \ \ #\ -----------------------------\n\ \ \ \ proc\ filterProjectedTagsInDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ return\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isProjectedTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Find\ a\ version\ tag\ that\ the\ camera\ saw\ and\ check\ its\ rotation\ to\n\ \ \ \ #\ figure\ out\ the\ model\ version\ that\ we're\ seeing.\n\ \ \ \ proc\ detectVersionFromDetectedTags\ \{detectedTags\}\ \{\n\ \ \ \ \ \ \ \ local\ proc\ getTagAngle\ \{tag\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ p\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{atan2(-1\ *\ (\[lindex\ \$p\ 1\ 1\]\ -\ \[lindex\ \$p\ 0\ 1\]),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lindex\ \$p\ 1\ 0\]\ -\ \[lindex\ \$p\ 0\ 0\])\}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Find\ any\ version\ tag.\ If\ none\ were\ detected,\ then\ abort\n\ \ \ \ \ \ \ \ #\ and\ wait\ until\ a\ later\ frame.\n\ \ \ \ \ \ \ \ foreach\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isVersionTag\ \$tag(id)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagId\ \$tag(id)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ versionTagAngle\ \[getTagAngle\ \$tag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ versionTagId\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ #\ Compare\ angle\ to\ angle\ of\ any\ other\ projected\ tag.\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$detectedTags\]\ <\ 2\}\ \{\ return\ \{\}\ \}\n\ \ \ \ \ \ \ \ foreach\ detectedTag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$detectedTag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[isProjectedTag\ \$id\]\ &&\ !\[isVersionTag\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ otherTagAngle\ \[getTagAngle\ \$detectedTag\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ otherTagAngle\]\}\ \{\ return\ \{\}\ \}\n\n\ \ \ \ \ \ \ \ set\ versionAngle\ \[expr\ \{\$versionTagAngle\ -\ \$otherTagAngle\}\]\n\ \ \ \ \ \ \ \ #\ Rotations\ corresponding\ to\ versions\ 0,\ 1,\ 2,\ 3:\n\ \ \ \ \ \ \ \ set\ possibleVersions\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ 1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ \ 1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -1\ \ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0\ -1\]\n\ \ \ \ \ \ \ \ #\ Which\ of\ the\ possibleVersions\ is\ versionAngle\ closest\ to?\n\ \ \ \ \ \ \ \ return\ \[lindex\ \[lsort-indices\ \[lmap\ \{x\ y\}\ \$possibleVersions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{sqrt((\$x\ -\ cos(\$versionAngle))**2\ +\ (\$y\ -\ sin(\$versionAngle))**2)\}\n\ \ \ \ \ \ \ \ \}\]\]\ 0\]\n\ \ \ \ \}\n\n\ \ \ \ proc\ meanTagsDifference\ \{tags1\ tags2\}\ \{\n\ \ \ \ \ \ \ \ set\ diffsum\ 0.0\n\ \ \ \ \ \ \ \ set\ ndiffs\ 0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$tags1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ cheat\ and\ only\ count\ printed\ tags\ so\ we\ don't\ have\ to\n\ \ \ \ \ \ \ \ \ \ \ \ #\ deal\ with\ versioning.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$tags2\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x1\ y1\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tags2\ \$id\ c\]\ x2\ y2\n\ \ \ \ \ \ \ \ \ \ \ \ set\ diffsum\ \[expr\ \{\$diffsum\ +\ sqrt((\$x1\ -\ \$x2)*(\$x1\ -\ \$x2)\ +\ (\$y1\ -\ \$y2)*(\$y1\ -\ \$y2))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ ndiffs\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$ndiffs\ ==\ 0\}\ \{\ return\ Inf\ \}\n\ \ \ \ \ \ \ \ return\ \[expr\ \{\$diffsum\ /\ \$ndiffs\}\]\n\ \ \ \ \}\n\}\]\n
<unknown> claims builtin-programs/calibrate/draw-model.folk has program code When\ display\ /display/ (
[ m141:0 (s215:0) ]
)<unknown> claims builtin-programs/calibrate/draw-model.folk has program code When\ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ draw\ calibration\ model\ /model/\ \\\n\ \ \ \ \ \ \ \ using\ model-to-display\ homography\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ with\ message\ /calibrationMessage/\ \{\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ innerToOuter\ \{center\ corner\ \{s\ 1.66666667\}\}\ \{\n\ \ \ \ \ \ \ \ set\ r\ \[sub\ \$corner\ \$center\]\n\ \ \ \ \ \ \ \ return\ \[add\ \$center\ \[scale\ \$s\ \$r\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\;\ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ set\ topLeftTag\ \ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\]\n\ \ \ \ set\ topRightTag\ \ \ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomRightTag\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\]\n\ \ \ \ set\ bottomLeftTag\ \ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\]\n\n\ \ \ \ set\ boardBorderScale\ \[expr\ \{1.66666667\ *\ 2\}\]\n\ \ \ \ set\ boardTopLeft\ \ \ \ \[innerToOuter\ \[dict\ get\ \$topLeftTag\ c\]\ \ \ \ \ \[lindex\ \[dict\ get\ \$topLeftTag\ p\]\ \ \ \ \ 3\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardTopRight\ \ \ \[innerToOuter\ \[dict\ get\ \$topRightTag\ c\]\ \ \ \ \[lindex\ \[dict\ get\ \$topRightTag\ p\]\ \ \ \ 2\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomRight\ \[innerToOuter\ \[dict\ get\ \$bottomRightTag\ c\]\ \[lindex\ \[dict\ get\ \$bottomRightTag\ p\]\ 1\]\ \$boardBorderScale\]\n\ \ \ \ set\ boardBottomLeft\ \[innerToOuter\ \[dict\ get\ \$bottomLeftTag\ c\]\ \ \[lindex\ \[dict\ get\ \$bottomLeftTag\ p\]\ \ 0\]\ \$boardBorderScale\]\n\n\ \ \ \ set\ boardToClipSpaceCorners\ \\\n\ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\ -1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ 0\ 1\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$displayWidth\ \$displayHeight\ 1\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$displayHeight\ -1\ 1\]\]\n\ \ \ \ set\ boardCanvasToClipSpace\ \[\$matLib\ estimateHomography\ \$boardToClipSpaceCorners\]\n\n\ \ \ \ set\ board\ \[list\ \$this\ board\]\n\ \ \ \ set\ boardCanvas\ \[list\ \$board\ canvas\]\n\ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ with\ width\ \$displayWidth\ height\ \$displayHeight\n\ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$boardCanvas\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$board\ has\ canvas\ \$boardCanvas\ with\ \{*\}\$opts\n\ \ \ \ \}\n\ \ \ \ Claim\ \$board\ has\ canvas\ projection\ \$boardCanvasToClipSpace\n\n\ \ \ \ set\ bgColor\ \[list\ 1\ 1\ 1\ 1\]\n\n\ \ \ \ When\ \$board\ has\ canvas\ /any/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::norm\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ on\ board:\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$boardCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 99\n\n\ \ \ \ \ \ \ \ #\ Draw\ AprilTags\ on\ board:\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerCorners\ \[lreverse\ \[dict\ get\ \$modelTag\ p\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelCenter\ \[dict\ get\ \$modelTag\ c\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayOuterCorners\ \[lmap\ modelInnerCorner\ \$modelInnerCorners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterCorner\ \[innerToOuter\ \$modelCenter\ \$modelInnerCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelOuterCorner\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ an\ AprilTag\ onto\ \$board\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ id\ \$id\ corners\ \$displayOuterCorners\ background\ \$bgColor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ White\ backdrop\ across\ whole\ projector\ area\ to\ hopefully\ make\n\ \ \ \ \ \ \ \ #\ the\ projected\ tags\ pop\ out\ more:\n\ \ \ \ \ \ \ \ set\ surfaceToClip\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\n\ \ \ \ \ \ \ \ set\ p0\ \[list\ -1\ -1\]\n\ \ \ \ \ \ \ \ set\ p1\ \[list\ 1\ -1\]\n\ \ \ \ \ \ \ \ set\ p2\ \[list\ 1\ 1\]\n\ \ \ \ \ \ \ \ set\ p3\ \[list\ -1\ 1\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p1\ \$p2\ \$p3\ \$bgColor\]\ layer\ 99\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$surfaceToClip\ \$p0\ \$p1\ \$p3\ \$bgColor\]\ layer\ 99\n\n\ \ \ \ \ \ \ \ set\ sides\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopLeft\ \$boardTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomRight\ \$boardBottomLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardBottomLeft\ \$boardTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$boardTopRight\ \$boardBottomRight\]\]\n\n\ \ \ \ \ \ \ \ foreach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ \ \ \ \ \ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ \ \ \ \ \ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ side\ \$sides\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$side\ start\ end\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayStart\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$start\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayEnd\ \ \ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$end\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[sub\ \$displayEnd\ \$displayStart\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayRadians\ \[expr\ \{atan2(-1*\[lindex\ \$v\ 1\],\ \[lindex\ \$v\ 0\])\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayCenter\ \[scale\ 0.5\ \[add\ \$displayStart\ \$displayEnd\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ textScale\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \[norm\ \$v\]\ 20\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$board\ with\ text\ \$calibrationMessage\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ radians\ \$displayRadians\ position\ \$displayCenter\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ anchor\ top\ color\ black\ layer\ 100\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Now\ draw\ the\ board\ image\ (which\ has\ the\ projected\ tags)\ onto\n\ \ \ \ \ \ \ \ #\ the\ display:\n\ \ \ \ \ \ \ \ set\ displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 1\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 1\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"image\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$displayWidth\ \$displayHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOpts\ texture\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ layer\ 100\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/calibrate/calibrate.folk has program code #\ calibrate.folk\ --\n#\ (
[ m145:0 (s226:0) ]
)<unknown> claims builtin-programs/calibrate/calibrate.folk has program code #\ calibrate.folk\ --\n#\n#\ \ \ \ \ Implements\ camera-projector\ calibration:\ generate\ a\ calibration\n#\ \ \ \ \ pattern\ PDF,\ have\ the\ user\ measure\ its\ real-world\ dimension,\ run\n#\ \ \ \ \ iterative\ projector-camera\ process\ to\ get\ various\ poses\ of\ the\n#\ \ \ \ \ printed\ tags\ alongside\ projected\ tags,\ do\ linear\ fit\ and\ then\n#\ \ \ \ \ nonlinear\ refinement\ to\ find\ intrinsic\ and\ extrinsic\ parameters\n#\ \ \ \ \ for\ the\ camera\ and\ projector.\n#\n#\ \ \ \ \ Closely\ based\ on\ the\ technique\ in\ Audet\ (2009):\n#\ \ \ \ \ http://www.ok.sc.e.titech.ac.jp/res/PCS/publications/procams2009.pdf\n#\n\npackage\ require\ linalg\n\nforeach\ p\ \{add\ norm\ sub\ scale\ matmul\n\ \ \ \ getelem\ transpose\ determineSVD\ shape\ mkIdentity\ show\n\ \ \ \ solvePGauss\ crossproduct\ getcol\ setcol\ unitLengthVector\ det\n\}\ \{\n\ \ \ \ namespace\ import\ ::math::linearalgebra::\$p\n\}\n\nHold!\ -key\ \{calibration\ poses\ max\}\ \\\n\ \ \ \ Claim\ the\ calibration\ poses\ max\ is\ 10\n\nWhen\ camera\ /camera/\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\ &\\\n\ \ \ \ \ display\ /display/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ the\ AprilTag\ detector\ maker\ is\ /makeAprilTagDetector/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ &\\\n\ \ \ \ \ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ to\ calibrate\ camera\ /camera/\ to\ display\ /display/\ \\\n\ \ \ \ \ \ \ \ \ using\ measurements\ /measurements/\ \{\n\n\ \ \ \ set\ printedSideLengthMm\ \[string\ trimright\ \$measurements(tagSideLength)\ mm\]\n\n\ \ \ \ fn\ makeAprilTagDetector\n\ \ \ \ set\ calibrationTagDetector\ \[makeAprilTagDetector\ \"tagStandard52h13\"\ 2.0\ 3\]\n\n\ \ \ \ set\ calibrationId\ \[clock\ milliseconds\]\n\n\ \ \ \ #\ VERY\ IMPORTANT:\ disable\ autofocus\ forever.\n\ \ \ \ catch\ \{\ exec\ v4l2-ctl\ --device=\$camera\ --set-ctrl=focus_automatic_continuous=0\ \}\n\n\ \ \ \ if\ \{\$cameraWidth\ <\ 1920\}\ \{\n\ \ \ \ \ \ \ \ set\ camResults\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...camOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$camResults\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ camOpts\ \[dict\ get\ \[lindex\ \$camResults\ 0\]\ camOpts\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$camOpts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Retract!\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$cameraWidth\ height\ \$cameraHeight\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ 1920\ height\ 1080\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ restore\ old\ camera\ resolution\ later\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"calibrate:\ Warning:\ camera\ \$camera\ has\ \[llength\ \$camResults\]\ use\ wishes\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ set\ tagSideLength\ 1.0\n\ \ \ \ set\ tagOuterLength\ \[expr\ \{\$tagSideLength\ *\ 10/6\}\]\n\ \ \ \ set\ pad\ \$tagSideLength\n\n\ \ \ \ #\ Unit\ model's\ 2D\ coordinates\ have\ inner\ tag\ side\ length\ of\ 1.0:\n\ \ \ \ #\ scale\ it\ to\ real-world\ coordinates.\n\ \ \ \ set\ printedSideLengthM\ \[/\ \$printedSideLengthMm\ 1000.0\]\n\ \ \ \ set\ baseModel\ \[\$modelLib\ scaleModel\ \[\$modelLib\ unitModel\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$printedSideLengthM\]\n\ \ \ \ set\ ROWS\ \[\$modelLib\ rows\]\n\ \ \ \ set\ COLS\ \[\$modelLib\ cols\]\n\n\ \ \ \ #\ A\ list\ of\ pose\ dictionaries.\ Each\ dictionary\ has\ entries\ `model`\n\ \ \ \ #\ and\ `H_modelToDisplay`\ ('prewarp'\ homography\ from\ model\ plane\ to\n\ \ \ \ #\ projector\ plane)\ and\ `tags`\ (tag\ ID\ =>\ dictionary\ of\ tag\n\ \ \ \ #\ detection\ info\ from\ camera\ and\ AprilTag\ detector)\ and\n\ \ \ \ #\ `displayResolution`\ and\ `cameraResolution`\ and\ `tagsSize`.\n\ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \[list\]\n\ \ \ \ On\ unmatch\ \{\ Hold!\ -key\ last-seen-poses\ \{\}\ \}\n\ \ \ \ set\ SEEN_POSES_MAX\ 3\n\n\ \ \ \ #\ The\ poses\ to\ use\ for\ actual\ calibration\ at\ the\ end.\ We'll\ want\n\ \ \ \ #\ at\ least\ 10\ poses\ to\ do\ ultimate\ calibration+refinement.\n\ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \[list\]\n\n\ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ 0\n\n\ \ \ \ #\ Project\ calibration\ tags\ based\ on\ the\ current\ model-to-display\n\ \ \ \ #\ homography\ (which\ gets\ dynamically\ updated\ as\ you\ move\ the\ board\n\ \ \ \ #\ around):\n\ \ \ \ When\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /poses/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ poses\ max\ is\ /posesMax/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ cycle\ time\ is\ /cycleTime/\ &\\\n\ \ \ \ \ \ \ \ \ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ with\ /...modelToDisplayOpts/\ \{\n\ \ \ \ \ \ \ \ set\ message\ \"\[llength\ \$poses\]/\$posesMax\ poses\ (\[expr\ \{round(\$cycleTime*1000)\}\]\ ms)\"\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ calibration\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ using\ model-to-display\ homography\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ message\ \$message\n\ \ \ \ \}\n\n\ \ \ \ #\ This\ is\ made\ a\ function\ so\ it\ can\ also\ be\ called\ by\ the\ Web\ page\n\ \ \ \ #\ when\ the\ user\ drags\ the\ slider\ to\ adjust\ projected\ tag\ scale.\n\ \ \ \ fn\ HoldDefaultModel!\ \{scale\}\ \{\n\ \ \ \ \ \ \ \ #\ Default\ model:\ just\ makes\ the\ tags\ fill\ most\ of\ the\ middle\n\ \ \ \ \ \ \ \ #\ of\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[::math::min\ \$(\$displayWidth/(\$COLS\ *\ (\$tagOuterLength\ +\ \$pad)))\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$displayHeight/(\$ROWS\ *\ (\$tagOuterLength\ +\ \$pad)))\]\n\ \ \ \ \ \ \ \ set\ tagSideLengthPixels\ \[expr\ \{\$tagSideLengthPixels\ *\ \$scale\}\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Center\ this\ on\ the\ projector\ area.\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ \$printedSideLengthM\ \$tagSideLengthPixels\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{\$printedSideLengthM\ 0\ \$tagSideLengthPixels\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ \$printedSideLengthM\ 0\ \$tagSideLengthPixels\}\n\ \ \ \ \ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \ \ \ \ \}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Default\ model\ and\ version:\ nothing\ rotated.\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ is\ \$H_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$baseModel\ version\ -1\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ Claim\ the\ calibration\ HoldDefaultModel!\ is\ \[fn\ HoldDefaultModel!\]\n\ \ \ \ HoldDefaultModel!\ 1.0\n\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ When\ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ \ \ \ \ -serially\ camera\ \$camera\ has\ gray\ frame\ /frame/\ at\ timestamp\ /frameTimestamp/\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ so\ we\ just\ lookup\ whatever\ is\ latest\ _right\ now_,\n\ \ \ \ \ \ \ \ #\ instead\ of\ subscribing.\n\ \ \ \ \ \ \ \ set\ calibrationStates\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[Query!\ the\ calibration\ model-to-display\ homography\ is\ /H_modelToDisplay/\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /...modelToDisplayOpts/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationStates\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Sort\ in\ ascending\ order\ to\ find\ the\ newest\ (highest\ frameTimestamp)\ model.\n\ \ \ \ \ \ \ \ set\ calibrationState\ \[lindex\ \[lsort\ -command\ \[list\ apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$a\ modelToDisplayOpts\ frameTimestamp\]\ <\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$b\ modelToDisplayOpts\ frameTimestamp\]\}\n\ \ \ \ \ \ \ \ \}\}\]\ \$calibrationStates\]\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ calibrationState\ \{\}\n\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$modelToDisplayOpts\ model\]\n\ \ \ \ \ \ \ \ set\ version\ \[dict\ get\ \$modelToDisplayOpts\ version\]\n\ \ \ \ \ \ \ \ set\ modelFrameTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ frameTimestamp\]\n\ \ \ \ \ \ \ \ set\ modelTimestamp\ \[dict\ get\ \$modelToDisplayOpts\ modelTimestamp\]\n\ \ \ \ \ \ \ \ if\ \{\$modelFrameTimestamp\ >=\ \$frameTimestamp\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ an\ old\ homography.\ This\ seems\ to\ only\ happen\ on\n\ \ \ \ \ \ \ \ \ \ \ \ #\ slider\ manual\ size\ adjust.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ aprilTime\ \[time\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[\$calibrationTagDetector\ detect\ \$frame\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ package\ require\ linalg\n\n\ \ \ \ \ \ \ \ #\ This\ runs\ every\ frame,\ looks\ at\ the\ detected\ tags\ (both\n\ \ \ \ \ \ \ \ #\ projected\ and\ printed),\ and\ updates\ the\ H_modelToDisplay\n\ \ \ \ \ \ \ \ #\ such\ that\ the\ projected\ tags\ should\ sit\ in\ the\ middle\ of\ the\n\ \ \ \ \ \ \ \ #\ calibration\ board.\n\n\ \ \ \ \ \ \ \ set\ printedTags\ \[dict\ create\]\ \;#\ dict\ keyed\ by\ tag\ id\ for\ easy\ lookup\n\ \ \ \ \ \ \ \ foreach\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ allDetectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ dict\ set\ printedTags\ \$id\ \$tag\ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ set\ printedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ printedTag\}\ \$printedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$printedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ printedPointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Describes\ how\ tags\ from\ the\ model\ that\ were\ printed\n\ \ \ \ \ \ \ \ #\ ended\ up\ mapping\ to\ camera\ coordinates.\n\ \ \ \ \ \ \ \ set\ H_modelToCameraViaPs\ \[\$matLib\ estimateHomography\ \$printedPointPairs\]\n\n\ \ \ \ \ \ \ \ #\ Map\ the\ bounds\ of\ the\ board\ to\ camera\ coordinates,\ so\ we\ can\n\ \ \ \ \ \ \ \ #\ check\ if\ projected\ tags\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ modelTopLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ 0\}\]\ p\]\ 3\]\n\ \ \ \ \ \ \ \ set\ modelTopRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ 0*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 2\]\n\ \ \ \ \ \ \ \ set\ modelBottomRight\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ \$COLS-1\}\]\ p\]\ 1\]\n\ \ \ \ \ \ \ \ set\ modelBottomLeft\ \[lindex\ \[dict\ get\ \$model\ \[expr\ \{48600\ +\ (\$ROWS-1)*\$COLS\ +\ 0\}\]\ p\]\ 0\]\n\ \ \ \ \ \ \ \ set\ printedCalibrationBoard\ \[list\ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopLeft\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelTopRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelBottomLeft\]\]\n\ \ \ \ \ \ \ \ set\ boardMinX\ 100000\;\ set\ boardMinY\ 100000\n\ \ \ \ \ \ \ \ set\ boardMaxX\ -100000\;\ set\ boardMaxY\ -100000\n\ \ \ \ \ \ \ \ foreach\ \{cornerX\ cornerY\}\ \$printedCalibrationBoard\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ <\ \$boardMinX\}\ \{\ set\ boardMinX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ <\ \$boardMinY\}\ \{\ set\ boardMinY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerX\ >\ \$boardMaxX\}\ \{\ set\ boardMaxX\ \$cornerX\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cornerY\ >\ \$boardMaxY\}\ \{\ set\ boardMaxY\ \$cornerY\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ count\ projected\ tags\ that\ are\ inside\ the\ board.\n\ \ \ \ \ \ \ \ set\ projectedTags\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \$allDetectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[dict\ get\ \$tag\ c\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ >\ \$boardMinX\ &&\ \$x\ <\ \$boardMaxX\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$y\ >\ \$boardMinY\ &&\ \$y\ <\ \$boardMaxY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ a\ projected\ tag\ that\ we\ detected.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ projectedTags\ \$id\ \$tag\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$projectedTags\]\ ==\ 0\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ if\ \{\$version\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ detectedVersion\ \[\$modelLib\ detectVersionFromDetectedTags\ \$tags\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ If\ the\ detected\ version\ does\ not\ correspond\ to\ version\n\ \ \ \ \ \ \ \ \ \ \ \ #\ mod\ 4,\ then\ we\ should\ abort\ and\ wait\ until\ a\ later\n\ \ \ \ \ \ \ \ \ \ \ \ #\ frame\ to\ proceed.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ expectedVersion\ \[expr\ \{\$version\ %\ 4\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$detectedVersion\ !=\ \$expectedVersion\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ projectedPointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectedPointPairs\ \[list\ \{*\}\$cameraCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ puts\ \"point\ pairs\ (camera\ ->\ display):\ \{\$projectedPointPairs\}\"\n\ \ \ \ \ \ \ \ set\ H_cameraToDisplay\ \[\$matLib\ estimateHomography\ \$projectedPointPairs\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[::math::linearalgebra::det\ \$H_cameraToDisplay\])\ <\ 0.001\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Garbage\ homography\ that\ just\ shrinks\ the\ points\ way\ down\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (https://stackoverflow.com/questions/10972438/detecting-garbage-homographies-from-findhomography-in-opencv).\n\ \ \ \ \ \ \ \ \ \ \ \ #\ It's\ sort\ of\ 'overfitted'\ and\ just\ has\ a\ big\ y-intercept\n\ \ \ \ \ \ \ \ \ \ \ \ #\ and\ will\ break\ everything\ if\ we\ let\ it\ through.\ Skip.\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Update\ H_modelToDisplay\ to\ project\ the\ tags\ into\ the\ right\n\ \ \ \ \ \ \ \ #\ spots\ on\ the\ board\ next\ frame.\n\ \ \ \ \ \ \ \ set\ nextH_modelToDisplay\ \[\$matLib\ matdMul\ \$H_cameraToDisplay\ \$H_modelToCameraViaPs\]\n\ \ \ \ \ \ \ \ set\ nextModelFrameTimestamp\ \$frameTimestamp\n\ \ \ \ \ \ \ \ set\ nextVersion\ \[+\ \$version\ 1\]\n\ \ \ \ \ \ \ \ set\ nextModel\ \[\$modelLib\ updateModelVersion\ \$baseModel\ \$nextVersion\]\n\ \ \ \ \ \ \ \ set\ nextModelTimestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\n\ \ \ \ \ \ \ \ #\ Check\ if\ any\ tag\ corners\ will\ be\ outside\ display\ bounds.\n\ \ \ \ \ \ \ \ foreach\ tagId\ \[dict\ keys\ \$nextModel\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tag\ \[dict\ get\ \$nextModel\ \$tagId\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ corners\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ corner\ \$corners\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$nextH_modelToDisplay\ \$corner\]\ x\ y\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 0\ ||\ \$x\ >\ \$displayWidth\ ||\ \$y\ <\ 0\ ||\ \$y\ >\ \$displayHeight\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Tag\ corner\ is\ outside\ display\ bounds\;\ skip\ this\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ update.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Hold!\ -key\ H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ model-to-display\ homography\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ is\ \$nextH_modelToDisplay\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ model\ \$nextModel\ version\ \$nextVersion\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ frameTimestamp\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ modelTimestamp\ \$nextModelTimestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ cycle-time\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ cycle\ time\ is\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$(\$nextModelTimestamp\ -\ \$modelTimestamp)\n\n\ \ \ \ \ \ \ \ #\ Should\ we\ record\ the\ points\ we\ just\ saw\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose?\n\n\ \ \ \ \ \ \ \ #\ We\ want\ to\ be\ seeing\ at\ least\ 50%\ of\ printed\ and\ projected\ tags.\n\ \ \ \ \ \ \ \ if\ \{\[dict\ size\ \$printedTags\]\ <\ \$COLS\ +\ \$ROWS\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ size\ \$projectedTags\]\ <\ \$COLS\ -\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ can\ do\ an\ error\ check\ here.\ H_modelToCameraViaPs\ was\n\ \ \ \ \ \ \ \ #\ derived\ above\ from\ printed\ tags\ --\ we\ should\ be\ able\ to\ run\n\ \ \ \ \ \ \ \ #\ _projected_\ tags\ through\ it\ and\ compare\ the\ coordinates\ to\n\ \ \ \ \ \ \ \ #\ the\ actual\ detection\ coordinates.\ If\ there's\ too\ much\ error,\n\ \ \ \ \ \ \ \ #\ we\ won't\ record\ this\ as\ a\ calibration\ pose.\n\ \ \ \ \ \ \ \ set\ totalError\ 0.0\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ projectedTag\}\ \$projectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$model\ \$id\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$projectedTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$cameraCorner\ cx\ cy\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Predicted\ camera\ x\ and\ y.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToCameraViaPs\ \$modelCorner\]\ px\ py\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dx\ \[-\ \$cx\ \$px\]\;\ set\ dy\ \[-\ \$cy\ \$py\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[expr\ \{\$dx*\$dx\ +\ \$dy*\$dy\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalError\ \[+\ \$totalError\ \$err\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ poseRmse\ \[expr\ \{sqrt(\$totalError\ /\ (\[llength\ \$projectedTags\]\ *\ 4))\}\]\n\ \ \ \ \ \ \ \ if\ \{\$poseRmse\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ Pose\ has\ too-high\ rmse\ (\$poseRmse)\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ pose\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ model\ \$model\ version\ \$version\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$camera\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraWidth\ \$cameraWidth\ cameraHeight\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ displayWidth\ \$displayWidth\ displayHeight\ \$displayHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSize\ \$printedSideLengthM\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ H_modelToDisplay\ \$H_modelToDisplay\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rmse\ \$poseRmse\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tags\ \[dict\ merge\ \$printedTags\ \$projectedTags\]\]\n\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ last-seen\ poses\ are\ /seenPoses/\n\ \ \ \ \ \ \ \ lappend\ seenPoses\ \$pose\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ >\ \$SEEN_POSES_MAX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ seenPoses\ \[lreplace\ \$seenPoses\ 0\ 0\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -key\ last-seen-poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ last-seen\ poses\ are\ \$seenPoses\n\n\ \ \ \ \ \ \ \ #\ Next,\ we\ check\ if\ projected\ tag\ corners\ have\ been\ pretty\n\ \ \ \ \ \ \ \ #\ stable\ in\ the\ last\ few\ frames.\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$seenPoses\]\ <\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ moved\ a\ lot\ since\ last\ frame,\ we're\ not\n\ \ \ \ \ \ \ \ #\ stable\ enough\ and\ shouldn't\ record\ this\ as\ a\ calibration\n\ \ \ \ \ \ \ \ #\ pose.\n\ \ \ \ \ \ \ \ foreach\ seenPose\ \[lrange\ \$seenPoses\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Decreasing\ this\ threshold\ to\ 1\ helps\ with\ data\n\ \ \ \ \ \ \ \ \ \ \ \ #\ accuracy.\ TODO:\ Use\ an\ _older_\ frame?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$seenPose(tags)\]\ >\ 5\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ puts\ \"WOULD\ APPEND\ CALIBRATION...\"\n\n\ \ \ \ \ \ \ \ #\ If\ the\ corners\ have\ _not_\ moved\ a\ lot\ since\ last\ _saved_\n\ \ \ \ \ \ \ \ #\ calibration\ pose,\ this\ isn't\ different\ enough\ to\ be\ a\ good\n\ \ \ \ \ \ \ \ #\ calibration\ pose\ to\ save.\n\ \ \ \ \ \ \ \ Expect!\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ /calibrationPoses/\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ prevCalibrationPose\ \[lindex\ \$calibrationPoses\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ meanTagsDifference\ \$pose(tags)\ \$prevCalibrationPose(tags)\]\ <\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Save\ the\ pose\ /\ camera\ image\ to\ a\ jpeg\ (for\ debugging\n\ \ \ \ \ \ \ \ #\ purposes).\n\ \ \ \ \ \ \ \ set\ imageName\ \"pose-\$calibrationId-\[llength\ \$calibrationPoses\].jpeg\"\n\ \ \ \ \ \ \ \ exec\ mkdir\ -p\ \"\$::env(HOME)/folk-calibration-poses\"\n\ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$frame\ \"\$::env(HOME)/folk-calibration-poses/\$imageName\"\n\ \ \ \ \ \ \ \ dict\ set\ pose\ imageName\ \$imageName\n\n\ \ \ \ \ \ \ \ #\ OK,\ let's\ save\ this\ calibration\ pose.\n\ \ \ \ \ \ \ \ lappend\ calibrationPoses\ \$pose\n\ \ \ \ \ \ \ \ puts\ \"calibrate:\ APPENDED\ CALIBRATION\ TO\ POSES\ (\[llength\ \$calibrationPoses\]\ poses\ collected)\"\n\ \ \ \ \ \ \ \ Hold!\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -version\ \$nextModelFrameTimestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\n\ \ \ \ \ \ \ \ #\ If\ we\ have\ enough\ poses,\ then\ stop\ the\ calibration\ process\n\ \ \ \ \ \ \ \ #\ (retract\ the\ printed\ side\ length?)\ and\ do\ a\ calibration.\ :-)\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ >=\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"calibrate:\ GOT\ ALL\ CALIBRATION\ POSES!\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Don't\ save\ the\ measurements\ until\ now,\ so\ the\ user\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ always\ safely\ abort\ calibration\ before\ this\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ having\ lasting\ effects.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration-measurements\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ measurements\ are\ \$measurements\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ from\ camera\ \$camera\ to\ display\ \$display\ are\ \$calibrationPoses\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Destroy\ the\ old\ calibration\ and\ trigger\ a\ new\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \{\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nfn\ processHomography\ \{H\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::getelem\n\ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\n\ \ \ \ fn\ h\ \{i\ j\}\ \{\ getelem\ \$H\ \[-\ \$j\ 1\]\ \[-\ \$i\ 1\]\ \}\n\n\ \ \ \ fn\ v\ \{i\ j\}\ \{\n\ \ \ \ \ \ \ \ list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 1\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 2\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 1\]\]\ \[*\ \[h\ \$i\ 1\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[+\ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 2\]\]\ \[*\ \[h\ \$i\ 2\]\ \[h\ \$j\ 3\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[*\ \[h\ \$i\ 3\]\ \[h\ \$j\ 3\]\]\n\ \ \ \ \}\n\n\ \ \ \ set\ V\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[v\ 1\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \[v\ 1\ 1\]\ \[v\ 2\ 2\]\]\]\n\ \ \ \ return\ \$V\n\}\n\n\n#\ Uses\ Zhang's\ calibration\ technique\n#\ (https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr98-71.pdf)\n#\ to\ calibrate\ a\ projector\ or\ camera\ given\ a\ known\ 2D\ planar\ pattern\n#\ and\ multiple\ observed\ poses.\n#\n#\ Returns\ intrinsic\ matrix\ for\ the\ camera/projector,\ which\ explains\n#\ how\ 3D\ real-world\ coordinates\ get\ projected\ to\ 2D\ coordinates\ by\n#\ that\ device.\ (The\ intrinsic\ matrix\ can\ be\ used\ with\ an\ AprilTag\n#\ detector\ to\ get\ real-world\ coordinates\ for\ each\ AprilTag.)\n#\n#\ Arguments:\n#\ \ \ \ \ \ \ \ \ width\ \ width\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ height\ height\ of\ camera\ or\ projector\ in\ pixels\n#\ \ \ \ \ \ \ \ \ Hs\ \ \ \ \ a\ list\ of\ N\ homographies\ from\ camera/projector\ image\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ plane\ ->\ model\ plane\ (for\ N\ different\ poses).\nfn\ zhangUnrefinedCalibrate\ \{name\ width\ height\ Hs\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::shape\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::transpose\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::determineSVD\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::mkIdentity\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::solvePGauss\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::getcol\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::scale\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::crossproduct\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\n\n\ \ \ \ #\ Try\ to\ solve\ for\ the\ camera\ intrinsics:\n\n\ \ \ \ #\ Construct\ V:\n\ \ \ \ set\ Vtop\ \[list\]\;\ set\ Vbottom\ \[list\]\n\ \ \ \ foreach\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ lassign\ \[processHomography\ \$H\]\ Vtop_\ Vbottom_\n\ \ \ \ \ \ \ \ lappend\ Vtop\ \$Vtop_\n\ \ \ \ \ \ \ \ lappend\ Vbottom\ \$Vbottom_\n\ \ \ \ \}\n\ \ \ \ set\ V\ \[list\ \{*\}\$Vtop\ \{*\}\$Vbottom\]\n\ \ \ \ assert\ \{\[shape\ \$V\]\ eq\ \[list\ \[*\ 2\ \[llength\ \$Hs\]\]\ 6\]\}\n\n\ \ \ \ #\ Solve\ Vb\ =\ 0:\n\ \ \ \ lassign\ \[determineSVD\ \[matmul\ \[transpose\ \$V\]\ \$V\]\]\ U\ S\ V\n\ \ \ \ set\ b\ \[lindex\ \[transpose\ \$V\]\ \[lindex\ \[lsort-indices\ \$S\]\ 0\]\]\n\n\ \ \ \ #\ Compute\ camera\ intrinsic\ matrix\ A:\n\ \ \ \ lassign\ \$b\ B11\ B12\ B22\ B13\ B23\ B33\n\ \ \ \ set\ v0\ \[expr\ \{(\$B12*\$B13\ -\ \$B11*\$B23)\ /\ (\$B11*\$B22\ -\ \$B12*\$B12)\}\]\n\ \ \ \ set\ lambda\ \[expr\ \{\$B33\ -\ (\$B13*\$B13\ +\ \$v0*(\$B12*\$B13\ -\ \$B11*\$B23))/\$B11\}\]\n\ \ \ \ set\ alpha\ \[expr\ \{sqrt(\$lambda/\$B11)\}\]\n\ \ \ \ set\ beta\ \[expr\ \{sqrt(\$lambda*\$B11/(\$B11*\$B22\ -\ \$B12*\$B12))\}\]\n\ \ \ \ set\ gamma\ \[expr\ \{-\$B12*\$alpha*\$alpha*\$beta/\$lambda\}\]\n\ \ \ \ set\ u0\ \[expr\ \{\$gamma*\$v0/\$beta\ -\ \$B13*\$alpha*\$alpha/\$lambda\}\]\n\ \ \ \ foreach\ var\ \{v0\ lambda\ alpha\ beta\ gamma\ u0\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"\$var\ =\ \[set\ \$var\]\"\n\ \ \ \ \}\n\n\ \ \ \ set\ fx\ \$alpha\;\ set\ fy\ \$beta\n\ \ \ \ set\ cx\ \$u0\;\ set\ cy\ \$v0\n\ \ \ \ set\ s\ \$gamma\n\ \ \ \ puts\ \"\ \ \ Focal\ Length:\ \\\[\ \$fx\ \$fy\ \]\"\n\ \ \ \ puts\ \"Principal\ Point:\ \\\[\ \$cx\ \$cy\ \]\"\n\ \ \ \ puts\ \"\ \ \ \ \ \ \ \ \ \ \ Skew:\ \\\[\ \$s\ \]\ \"\n\n\ \ \ \ #\ Intrinsic\ matrix:\n\ \ \ \ set\ A\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{\$fx\ \ \$s\ \ \ \$cx\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ \$fy\ \ \$cy\}\n\ \ \ \ \ \ \ \ \{0\ \ \ \ 0\ \ \ \ 1\}\n\ \ \ \ \}\]\n\ \ \ \ set\ Ainv\ \[solvePGauss\ \$A\ \[mkIdentity\ 3\]\]\n\n\ \ \ \ set\ extrinsics\ \[lmap\ H\ \$Hs\ \{\n\ \ \ \ \ \ \ \ set\ h1\ \[getcol\ \$H\ 0\]\n\ \ \ \ \ \ \ \ set\ h2\ \[getcol\ \$H\ 1\]\n\ \ \ \ \ \ \ \ set\ h3\ \[getcol\ \$H\ 2\]\n\ \ \ \ \ \ \ \ set\ lambda\ \[/\ 1.0\ \[norm\ \[matmul\ \$Ainv\ \$h1\]\]\]\n\n\ \ \ \ \ \ \ \ set\ r1\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h1\]\]\n\ \ \ \ \ \ \ \ set\ r2\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h2\]\]\n\ \ \ \ \ \ \ \ set\ r3\ \[crossproduct\ \$r1\ \$r2\]\n\ \ \ \ \ \ \ \ set\ R\ \[transpose\ \[list\ \$r1\ \$r2\ \$r3\]\]\n\n\ \ \ \ \ \ \ \ set\ t\ \[scale\ \$lambda\ \[matmul\ \$Ainv\ \$h3\]\]\n\n\ \ \ \ \ \ \ \ #\ Refine\ R\ into\ a\ better\ rotation\ matrix\ (reorthogonalize)\n\ \ \ \ \ \ \ \ #\ using\ SVD.\n\ \ \ \ \ \ \ \ lassign\ \[determineSVD\ \$R\]\ U\ S\ V\n\ \ \ \ \ \ \ \ set\ R\ \[matmul\ \$U\ \[transpose\ \$V\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ R\ \$R\ t\ \$t\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Initialize\ distortion\ terms\ k1\ and\ k2\ to\ 0\ --\ they\ get\ figured\n\ \ \ \ #\ out\ during\ nonlinear\ refinement.\n\ \ \ \ set\ intrinsics\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ \$width\ height\ \$height\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fx\ \$fx\ fy\ \$fy\ cx\ \$cx\ cy\ \$cy\ s\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k1\ 0\ k2\ 0\ p1\ 0\ p2\ 0\]\n\ \ \ \ return\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ name\ \$name\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ intrinsics\ \$intrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \$extrinsics\]\n\}\n\nfn\ setCameraToProjectorExtrinsics\ \{modelLib\ calibrationVar\ calibrationPoses\}\ \{\n\ \ \ \ #\ Use\ the\ \"Kabsch\ algorithm\"\ (https://nghiaho.com/?page_id=671\;\n\ \ \ \ #\ https://zpl.fi/aligning-point-patterns-with-kabsch-umeyama-algorithm/)\n\ \ \ \ #\ to\ find\ the\ rotation\ and\ translation\ from\ 3D\ camera-space\ to\ 3D\n\ \ \ \ #\ projector-space.\n\n\ \ \ \ upvar\ \$calibrationVar\ cal\n\n\ \ \ \ #\ Let's\ take\ all\ the\ points\ for\ which\ we\ have\ a\ corresponding\n\ \ \ \ #\ camera\ frame\ point\ and\ projector\ frame\ point.\n\ \ \ \ set\ cameraFramePoints\ \[list\]\n\ \ \ \ set\ projectorFramePoints\ \[list\]\n\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ calibrationPose\ \[lindex\ \$calibrationPoses\ \$i\]\n\n\ \ \ \ \ \ \ \ set\ Rc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ camera\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ set\ Rp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ R\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$cal\ projector\ extrinsics\]\ \$i\]\ t\]\n\n\ \ \ \ \ \ \ \ #\ TODO:\ Try\ using\ pose\ estimation\ instead?\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$calibrationPose\ model\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ k\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ v\ \[dict\ get\ \$tag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ k\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ v\ 0.0\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vc\ \[add\ \[matmul\ \$Rc\ \$v\]\ \$tc\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vp\ \[add\ \[matmul\ \$Rp\ \$v\]\ \$tp\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraFramePoints\ \$vc\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorFramePoints\ \$vp\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ puts\ \"cameraFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$cameraFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\ \ \ \ #\ puts\ \"projectorFramePoints\ =\ \\\[\[join\ \[lmap\ p\ \$projectorFramePoints\ \{concat\ \\\[\ \[join\ \$p\ ,\]\ \\\]\}\]\ ,\\n\]\\\]\"\n\n\ \ \ \ set\ n\ \[llength\ \$cameraFramePoints\]\n\n\ \ \ \ set\ vcsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vc\ \$cameraFramePoints\ \{\ set\ vcsum\ \[add\ \$vcsum\ \$vc\]\ \}\n\ \ \ \ set\ cameraFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vcsum\]\n\n\ \ \ \ set\ vpsum\ \{0\ 0\ 0\}\n\ \ \ \ foreach\ vp\ \$projectorFramePoints\ \{\ set\ vpsum\ \[add\ \$vpsum\ \$vp\]\ \}\n\ \ \ \ set\ projectorFramePointsCentroid\ \[scale\ \[/\ 1.0\ \$n\]\ \$vpsum\]\n\n\ \ \ \ set\ H\ \[matmul\ \[transpose\ \[sub\ \$cameraFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$cameraFramePointsCentroid\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[sub\ \$projectorFramePoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[lrepeat\ \$n\ \$projectorFramePointsCentroid\]\]\]\n\n\ \ \ \ lassign\ \[determineSVD\ \$H\]\ U\ S\ V\n\ \ \ \ set\ R\ \[matmul\ \$V\ \[transpose\ \$U\]\]\n\ \ \ \ set\ t\ \[sub\ \$projectorFramePointsCentroid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$R\ \$cameraFramePointsCentroid\]\]\n\n\ \ \ \ dict\ set\ cal\ R_cameraToProjector\ \$R\n\ \ \ \ dict\ set\ cal\ t_cameraToProjector\ \$t\n\}\n\n#\ End-to-end\ calibrates\ a\ camera-projector\ pair.\ calibrationPoses\ is\n#\ a\ list\ of\ N\ pose\ dictionaries.\ Each\ pose\ dictionary\ includes\ `tags`\n#\ from\ a\ camera\ detection,\ `model`\ with\ coordinates\ in\ meters,\n#\ `H_modelToDisplay`.\nfn\ unrefinedCalibrateCameraAndProjector\ \{modelLib\ matLib\ calibrationPoses\}\ \{\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::det\n\ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ #\ Just\ used\ to\ get\ metadata\ about\ cam/proj:\n\ \ \ \ set\ pose0\ \[lindex\ \$calibrationPoses\ 0\]\n\n\ \ \ \ #\ First,\ calibrate\ the\ camera.\ \"Using\ only\ the\ corners\ from\n\ \ \ \ #\ printed\ markers\ xb\ and\ their\ detected\ corners\ xc,\ \[...\]\n\ \ \ \ #\ calibrate\ the\ camera\ with\ no\ difficulties\ using\ Zhang’s\ method.\"\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToCamera\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ #\ Pairs\ of\ (camera\ coordinates,\ model\ coordinates).\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ set\ tags\ \[dict\ get\ \$pose\ tags\]\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ cameraTag\}\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelTag\ \[dict\ get\ \$model\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cameraCorner\ \[dict\ get\ \$cameraTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$cameraCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ H\ \[\$matLib\ estimateHomography\ \$pointPairs\]\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H\ \[scale\ -1\ \$H\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ camera:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ cameraName\ \[dict\ get\ \$pose0\ camera\]\n\ \ \ \ set\ cameraWidth\ \[dict\ get\ \$pose0\ cameraWidth\]\n\ \ \ \ set\ cameraHeight\ \[dict\ get\ \$pose0\ cameraHeight\]\n\ \ \ \ set\ cameraCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$cameraName\ \$cameraWidth\ \$cameraHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToCamera\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ #\ Second,\ calibrate\ the\ projector.\n\ \ \ \ set\ i\ 0\n\ \ \ \ set\ Hs_modelToDisplay\ \[lmap\ pose\ \$calibrationPoses\ \{\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ set\ pointPairs\ \[list\]\n\ \ \ \ \ \ \ \ set\ model\ \[dict\ get\ \$pose\ model\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$modelTag\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ displayCorner\ \[\$matLib\ applyHomography\ \$H_modelToDisplay\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ pointPairs\ \[list\ \{*\}\$modelCorner\ \{*\}\$displayCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[det\ \$H_modelToDisplay\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ H_modelToDisplay\ \[scale\ -1\ \$H_modelToDisplay\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ H_modelToDisplay\n\ \ \ \ \}\]\n\ \ \ \ puts\ \"Zhang\ calibrate\ projector:\"\n\ \ \ \ puts\ \"========\"\n\ \ \ \ set\ projectorName\ \[dict\ get\ \$pose0\ display\]\n\ \ \ \ set\ projectorWidth\ \[dict\ get\ \$pose0\ displayWidth\]\n\ \ \ \ set\ projectorHeight\ \[dict\ get\ \$pose0\ displayHeight\]\n\ \ \ \ set\ projectorCalibration\ \[zhangUnrefinedCalibrate\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorName\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$projectorWidth\ \$projectorHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$Hs_modelToDisplay\]\n\ \ \ \ puts\ \"\\n======================\\n\"\n\n\ \ \ \ set\ calibration\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera\ \$cameraCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ projector\ \$projectorCalibration\]\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\ \ \ \ return\ \$calibration\n\}\n\nWhen\ the\ calibration\ model\ library\ is\ /modelLib/\ &\\\n\ \ \ \ \ the\ calibration\ matrix\ library\ is\ /matLib/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ max\ is\ /calibrationPosesMax/\ &\\\n\ \ \ \ \ the\ calibration\ poses\ from\ camera\ /camera/\ to\ display\ /display/\ are\ /calibrationPoses/\ &\\\n\ \ \ \ \ /nobody/\ claims\ a\ calibration\ from\ camera\ /camera/\ to\ display\ /display/\ is\ /anything/\ &\\\n\ \ \ \ \ the\ calibration\ refiner\ is\ /refineCalibration/\ \{\n\n\ \ \ \ if\ \{\[llength\ \$calibrationPoses\]\ <\ \$calibrationPosesMax\}\ \{\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibration\ \[unrefinedCalibrateCameraAndProjector\ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\]\n\ \ \ \ puts\ \"========\ Unrefined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \"\"\n\n\ \ \ \ set\ calibration\ \[\{*\}\$refineCalibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$modelLib\ \$matLib\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[fn\ setCameraToProjectorExtrinsics\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$calibrationPoses\ \$calibration\]\n\ \ \ \ puts\ \"========\ Refined\ calibration\ intrinsics\ =========\"\n\n\ \ \ \ puts\ \".\"\n\ \ \ \ puts\ \"========\ Refined\ calibration\ =========\"\n\ \ \ \ puts\ \$calibration\n\ \ \ \ puts\ \".\"\n\n\ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ Claim\ a\ calibration\ from\ camera\ \$camera\ to\ display\ \$display\ is\ \$calibration\n\}\n
<unknown> claims builtin-programs/calibrate/matlib.folk has program code When\ libapriltag\ has\ been (
[ m146:0 (s222:0) ]
)<unknown> claims builtin-programs/calibrate/matlib.folk has program code When\ libapriltag\ has\ been\ built\ with\ config\ /configCcWithLibapriltag/\ \{\nfn\ configCcWithLibapriltag\n\n#\ We\ try\ to\ use\ the\ AprilTag\ matrix\ library\ (instead\ of\ tcllib\ linalg)\n#\ to\ do\ matrix/homography\ operations\ in\ the\ live\ calibration\ inner\n#\ loop,\ to\ help\ with\ performance:\nset\ cc\ \[C\]\nconfigCcWithLibapriltag\ \$cc\n\$cc\ include\ <math.h>\n\$cc\ include\ <common/matd.h>\n\$cc\ include\ <common/homography.h>\n\n\$cc\ code\ \{\n\ \ \ \ extern\ Jim_ObjType\ matd_ObjType\;\n\ \ \ \ void\ matd_freeIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_destroy((matd_t*)\ objPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_dupIntRepProc(Jim_Interp\ *interp,\ Jim_Obj\ *srcPtr,\ Jim_Obj\ *dupPtr)\ \{\n\ \ \ \ \ \ \ \ dupPtr->internalRep.ptr\ =\ (void*)\ matd_copy((matd_t*)\ srcPtr->internalRep.ptr)\;\n\ \ \ \ \}\n\ \ \ \ void\ matd_updateStringProc(Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ (matd_t\ *)objPtr->internalRep.ptr\;\n\n\ \ \ \ \ \ \ \ objPtr->bytes\ =\ Jim_Alloc(mat->nrows\ *\ (1\ +\ mat->ncols\ *\ 26\ +\ 1))\;\n\ \ \ \ \ \ \ \ char\ *s\ =\ objPtr->bytes\;\n\ \ \ \ \ \ \ \ int\ i\ =\ 0\;\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ for\ (unsigned\ int\ row\ =\ 0\;\ row\ <\ mat->nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\{'\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (unsigned\ int\ col\ =\ 0\;\ col\ <\ mat->ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ n\ =\ snprintf(&s\[i\],\ 26,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%f\ \",\ MATD_EL(mat,\ row,\ col))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ENSURE(n\ <=\ 26)\;\ i\ +=\ n\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ s\[i++\]\ =\ '\}'\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ s\[i\]\ =\ 0\;\n\ \ \ \ \ \ \ \ objPtr->length\ =\ strlen(s)\;\n\ \ \ \ \}\n\ \ \ \ int\ matd_setFromAnyProc(Jim_Interp\ *interp,\ Jim_Obj\ *objPtr)\ \{\n\ \ \ \ \ \ \ \ //\ shimmer\ into\ a\ list,\ then\ iterate\n\ \ \ \ \ \ \ \ int\ nrows\;\ Jim_Obj\ *rowObj0\;\n\ \ \ \ \ \ \ \ nrows\ =\ Jim_ListLength(interp,\ objPtr)\;\n\ \ \ \ \ \ \ \ __ENSURE(nrows\ >\ 0)\;\n\ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ 0,\ &rowObj0,\ false))\;\n\ \ \ \ \ \ \ \ int\ ncols\ =\ Jim_ListLength(interp,\ rowObj0)\;\n\ \ \ \ \ \ \ \ __ENSURE(ncols\ >\ 0)\;\n\n\ \ \ \ \ \ \ \ matd_t\ *mat\ =\ matd_create(nrows,\ ncols)\;\n\ \ \ \ \ \ \ \ for\ (int\ row\ =\ 0\;\ row\ <\ nrows\;\ row++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *rowObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ objPtr,\ row,\ &rowObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ rowCols\ =\ Jim_ListLength(interp,\ rowObj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(rowCols\ ==\ ncols)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ col\ =\ 0\;\ col\ <\ ncols\;\ col++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_ListIndex(interp,\ rowObj,\ col,\ &elObj,\ false))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ elObj,\ &MATD_EL(mat,\ row,\ col)))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ objPtr->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \ \ \ \ objPtr->internalRep.ptr\ =\ mat\;\n\ \ \ \ \ \ \ \ return\ JIM_OK\;\n\ \ \ \ \}\n\ \ \ \ Jim_ObjType\ matd_ObjType\ =\ (Jim_ObjType)\ \{\n\ \ \ \ \ \ \ \ .name\ =\ \"matd_t*\",\n\ \ \ \ \ \ \ \ .freeIntRepProc\ =\ matd_freeIntRepProc,\n\ \ \ \ \ \ \ \ .dupIntRepProc\ =\ matd_dupIntRepProc,\n\ \ \ \ \ \ \ \ .updateStringProc\ =\ matd_updateStringProc,\n\ \ \ \ \ \ \ \ /*\ .setFromAnyProc\ =\ matd_setFromAnyProc,\ */\n\ \ \ \ \}\;\n\}\n\$cc\ argtype\ matd_t*\ \{\n\ \ \ \ __ENSURE_OK(matd_setFromAnyProc(interp,\ \$obj))\;\n\ \ \ \ matd_t*\ \$argname\;\n\ \ \ \ \$argname\ =\ (matd_t*)\ \$obj->internalRep.ptr\;\n\}\n\$cc\ rtype\ matd_t*\ \{\n\ \ \ \ \$robj\ =\ Jim_NewObj(interp)\;\n\ \ \ \ \$robj->bytes\ =\ NULL\;\n\ \ \ \ \$robj->typePtr\ =\ &matd_ObjType\;\n\ \ \ \ \$robj->internalRep.ptr\ =\ \$rvalue\;\n\}\n\n\$cc\ proc\ computeNormalizer\ \{int\ nPoints\ float\ points\[\]\[2\]\}\ matd_t*\ \{\n\ \ \ \ double\ cx\ =\ 0,\ cy\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ cx\ +=\ points\[i\]\[0\]\;\ cy\ +=\ points\[i\]\[1\]\;\n\ \ \ \ \}\n\ \ \ \ cx\ /=\ nPoints\;\ cy\ /=\ nPoints\;\n\n\ \ \ \ double\ avgDist\ =\ 0\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPoints\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ dx\ =\ points\[i\]\[0\]\ -\ cx\;\n\ \ \ \ \ \ \ \ double\ dy\ =\ points\[i\]\[1\]\ -\ cy\;\n\ \ \ \ \ \ \ \ avgDist\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \}\n\ \ \ \ avgDist\ /=\ nPoints\;\n\n\ \ \ \ double\ scale\ =\ sqrt(2.0)\ /\ avgDist\;\n\n\ \ \ \ matd_t\ *normalizer\ =\ matd_create(3,\ 3)\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 0)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 1)\ =\ scale\;\n\ \ \ \ MATD_EL(normalizer,\ 2,\ 2)\ =\ 1.0\;\n\ \ \ \ MATD_EL(normalizer,\ 0,\ 2)\ =\ -scale\ *\ cx\;\n\ \ \ \ MATD_EL(normalizer,\ 1,\ 2)\ =\ -scale\ *\ cy\;\n\n\ \ \ \ return\ normalizer\;\n\}\n\n\$cc\ code\ \{\n\ \ \ \ static\ void\ homographyProject(const\ matd_t\ *H,\ double\ x,\ double\ y,\ double\ *ox,\ double\ *oy)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ double\ xx\ =\ MATD_EL(H,\ 0,\ 0)*x\ +\ MATD_EL(H,\ 0,\ 1)*y\ +\ MATD_EL(H,\ 0,\ 2)\;\n\ \ \ \ \ \ \ \ double\ yy\ =\ MATD_EL(H,\ 1,\ 0)*x\ +\ MATD_EL(H,\ 1,\ 1)*y\ +\ MATD_EL(H,\ 1,\ 2)\;\n\ \ \ \ \ \ \ \ double\ zz\ =\ MATD_EL(H,\ 2,\ 0)*x\ +\ MATD_EL(H,\ 2,\ 1)*y\ +\ MATD_EL(H,\ 2,\ 2)\;\n\n\ \ \ \ \ \ \ \ *ox\ =\ xx\ /\ zz\;\n\ \ \ \ \ \ \ \ *oy\ =\ yy\ /\ zz\;\n\ \ \ \ \}\n\}\n\n#\ Takes\ a\ list\ of\ at\ least\ 4\ point\ pairs\ (model\ ->\ image)\ like\n#\n#\ \[list\ \\\n#\ \ \ \[list\ x0\ y0\ u0\ v0\]\]\ \\\n#\ \ \ \[list\ x1\ y1\ u1\ v1\]\ \\\n#\ \ \ \[list\ x2\ y2\ u2\ v2\]\ \\\n#\ \ \ \[list\ x3\ y3\ u3\ v3\]\]\n#\n#\ Returns\ a\ 3x3\ homography\ that\ maps\ model\ (x,\ y)\ to\ image\ (u,\ v)\n#\ (using\ homogeneous\ coordinates).\n\$cc\ code\ \{\n\ \ \ \ static\ matd_t\ *estimateHomographyBaseImpl(int\ nPointPairs,\ float\ pointPairs\[\]\[4\])\;\n\ \ \ \ static\ void\ refineHomography(int\ nPointPairs,\ float\ pointPairs\[\]\[4\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t\ *H)\;\n\}\n\$cc\ proc\ estimateHomography\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ matd_t\ *H\ =\ estimateHomographyBaseImpl(nPointPairs,\ pointPairs)\;\n\ \ \ \ refineHomography(nPointPairs,\ pointPairs,\ H)\;\n\ \ \ \ return\ H\;\n\}\n\n\$cc\ proc\ estimateHomographyBaseImpl\ \{float\[nPointPairs\]\[4\]\ pointPairs\}\ matd_t*\ \{\n\ \ \ \ float\ xys\[nPointPairs\]\[2\]\;\n\ \ \ \ float\ uvs\[nPointPairs\]\[2\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ xys\[i\]\[0\]\ =\ pointPairs\[i\]\[0\]\;\ xys\[i\]\[1\]\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ uvs\[i\]\[0\]\ =\ pointPairs\[i\]\[2\]\;\ uvs\[i\]\[1\]\ =\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T\ that\ normalizes\ model\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T\ =\ computeNormalizer(nPointPairs,\ xys)\;\n\n\ \ \ \ //\ Compute\ a\ similarity\ transformation\ T'\ that\ normalizes\ image\n\ \ \ \ //\ points.\n\ \ \ \ matd_t\ *T_\ =\ computeNormalizer(nPointPairs,\ uvs)\;\n\n\ \ \ \ //\ Apply\ DLT\ to\ obtain\ a\ homography\ H.\n\n\ \ \ \ matd_t\ *A\ =\ matd_create(2*nPointPairs,\ 9)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ double\ x,\ y\;\n\ \ \ \ \ \ \ \ homographyProject(T,\ xys\[i\]\[0\],\ xys\[i\]\[1\],\ &x,\ &y)\;\n\ \ \ \ \ \ \ \ double\ u,\ v\;\n\ \ \ \ \ \ \ \ homographyProject(T_,\ uvs\[i\]\[0\],\ uvs\[i\]\[1\],\ &u,\ &v)\;\n\n\ \ \ \ \ \ \ \ double\ row0\[9\]\ =\ \{x,\ y,\ 1,\ 0,\ 0,\ 0,\ -u*x,\ -u*y,\ -u\}\;\n\ \ \ \ \ \ \ \ double\ row1\[9\]\ =\ \{0,\ 0,\ 0,\ x,\ y,\ 1,\ -v*x,\ -v*y,\ -v\}\;\n\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 9\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i,\ j)\ =\ row0\[j\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(A,\ 2*i+1,\ j)\ =\ row1\[j\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ matd_svd_t\ svd\ =\ matd_svd_flags(A,\ MATD_SVD_NO_WARNINGS)\;\n\ \ \ \ matd_destroy(A)\;\n\n\ \ \ \ //\ H'\ =\ V\[-1\].reshape(3,\ 3)\n\ \ \ \ //\ H'\ /=\ H'\[2,\ 2\]\n\ \ \ \ matd_t\ *H_\ =\ matd_create(3,\ 3)\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 3\;\ i++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ j\ =\ 0\;\ j\ <\ 3\;\ j++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ MATD_EL(H_,\ i,\ j)\ =\ MATD_EL(svd.V,\ 3*i+j,\ svd.V->ncols-1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ matd_destroy(svd.U)\;\n\ \ \ \ matd_destroy(svd.S)\;\n\ \ \ \ matd_destroy(svd.V)\;\n\n\ \ \ \ matd_scale_inplace(H_,\ 1.0\ /\ MATD_EL(H_,\ 2,\ 2))\;\n\n\ \ \ \ //\ Set\ H\ =\ inv(T_)\ *\ H'\ *\ T.\n\ \ \ \ matd_t\ *H\ =\ matd_op(\"M^-1\ *\ M\ *\ M\",\ T_,\ H_,\ T)\;\n\ \ \ \ matd_destroy(T)\;\n\ \ \ \ matd_destroy(T_)\;\n\ \ \ \ matd_destroy(H_)\;\n\ \ \ \ return\ H\;\n\}\n\n#\ The\ refinement\ code\ is\ based\ on\ how\ OpenCV\ uses\ LMSolver\ in\ findHomography:\n#\ https://github.com/opencv/opencv/blob/9cdd525bc59b34a3db8f6db905216c5398ca93d6/modules/calib3d/src/fundam.cpp\n\$cc\ cflags\ -I./vendor/cmpfit\n\$cc\ include\ <float.h>\n\$cc\ include\ \"mpfit.h\"\n\$cc\ include\ \"mpfit.c\"\n\$cc\ proc\ refineHomography\ \{int\ nPointPairs\ float\[\]\[4\]\ pointPairs\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ matd_t*\ H\}\ void\ \{\n\ \ \ \ mp_result\ result\ =\ \{0\}\;\n\ \ \ \ mpfit(refineHomographyComputeError,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ error\ functions:\n\ \ \ \ \ \ \ \ \ \ nPointPairs\ *\ 2,\n\ \ \ \ \ \ \ \ \ \ //\ Number\ of\ parameters\ to\ optimize:\n\ \ \ \ \ \ \ \ \ \ 9,\n\ \ \ \ \ \ \ \ \ \ H->data,\ NULL,\n\ \ \ \ \ \ \ \ \ \ NULL,\n\ \ \ \ \ \ \ \ \ \ pointPairs,\n\ \ \ \ \ \ \ \ \ \ &result)\;\n\}\n\$cc\ code\ \{\n\ \ \ \ int\ refineHomographyComputeError(int\ m,\ int\ n,\ double\ *h,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ *errptr,\ double\ **dvec,\ void\ *private_data)\ \{\n\ \ \ \ \ \ \ \ float\ (*pointPairs)\[4\]\ =\ (float\ (*)\[4\])private_data\;\n\ \ \ \ \ \ \ \ int\ nPointPairs\ =\ m\ /\ 2\;\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ nPointPairs\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ double\ Mx\ =\ pointPairs\[i\]\[0\],\ My\ =\ pointPairs\[i\]\[1\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ ww\ =\ h\[6\]*Mx\ +\ h\[7\]*My\ +\ h\[8\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ ww\ =\ fabs(ww)\ >\ DBL_EPSILON\ ?\ 1./ww\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ xi\ =\ (h\[0\]*Mx\ +\ h\[1\]*My\ +\ h\[2\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ double\ yi\ =\ (h\[3\]*Mx\ +\ h\[4\]*My\ +\ h\[5\])*ww\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2\]\ =\ xi\ -\ pointPairs\[i\]\[2\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ errptr\[i*2+1\]\ =\ yi\ -\ pointPairs\[i\]\[3\]\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \}\n\}\n\n\$cc\ proc\ applyHomography\ \{matd_t*\ H\ double\[2\]\ xy\}\ Jim_Obj*\ \{\n\ \ \ \ double\ out\[2\]\;\n\ \ \ \ homography_project(H,\ xy\[0\],\ xy\[1\],\ &out\[0\],\ &out\[1\])\;\n\n\ \ \ \ Jim_Obj*\ retObjs\[2\]\ =\ \{\ Jim_NewDoubleObj(interp,\ out\[0\]),\ Jim_NewDoubleObj(interp,\ out\[1\])\ \}\;\n\ \ \ \ return\ Jim_NewListObj(interp,\ retObjs,\ 2)\;\n\}\n\$cc\ proc\ matdMul\ \{matd_t*\ a\ matd_t*\ b\}\ matd_t*\ \{\n\ \ \ \ return\ matd_multiply(a,\ b)\;\n\}\nset\ matLib\ \[\$cc\ compile\]\nClaim\ the\ calibration\ matrix\ library\ is\ \$matLib\n\n\}\n
<unknown> claims builtin-programs/gpu/enumerate.folk has program code {set cc [C]
$cc cflags -I./vend (
[ m147:0 (s223:0) ]
)<unknown> claims builtin-programs/gpu/enumerate.folk has program code {set cc [C]
$cc cflags -I./vendor
$cc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
$cc proc enumerateDisplays {} Jim_Obj* {
FOLK_ENSURE(volkInitialize() == VK_SUCCESS);
// Create a minimal Vulkan instance for display enumeration.
VkInstance instance;
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* enabledExtensions[] = {
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
#ifdef __APPLE__
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
createInfo.ppEnabledExtensionNames = enabledExtensions;
#ifdef __APPLE__
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
if (res == VK_ERROR_EXTENSION_NOT_PRESENT) {
FOLK_ERROR("Unable to enumerate displays (for example, this doesn't work on macOS)");
}
FOLK_ERROR("Failed to create Vulkan instance: %d", res);
}
}
volkLoadInstance(instance);
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
vkDestroyInstance(instance, NULL);
return Jim_NewListObj(interp, NULL, 0);
}
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
Jim_Obj *allDisplaysList = Jim_NewListObj(interp, NULL, 0);
// Enumerate displays for each physical device
for (uint32_t devIdx = 0; devIdx < physicalDeviceCount; devIdx++) {
VkPhysicalDevice physicalDevice = physicalDevices[devIdx];
uint32_t displayCount;
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, NULL);
VkDisplayPropertiesKHR displayProps[displayCount];
vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayCount, displayProps);
for (uint32_t i = 0; i < displayCount; i++) {
uint32_t modeCount;
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, NULL);
VkDisplayModePropertiesKHR modeProps[modeCount];
vkGetDisplayModePropertiesKHR(physicalDevice, displayProps[i].display,
&modeCount, modeProps);
Jim_Obj *modesList = Jim_NewListObj(interp, NULL, 0);
for (uint32_t j = 0; j < modeCount; j++) {
Jim_Obj *modeDict = Jim_ObjPrintf("visibleRegion {%u %u} refreshRate %u",
modeProps[j].parameters.visibleRegion.width,
modeProps[j].parameters.visibleRegion.height,
modeProps[j].parameters.refreshRate);
Jim_ListAppendElement(interp, modesList, modeDict);
}
int modesLen;
const char *modesStr = Jim_GetString(modesList, &modesLen);
Jim_Obj *displayDict = Jim_ObjPrintf("name {%s} physicalDimensions {%u %u} "
"physicalResolution {%u %u} modes {%s}",
displayProps[i].displayName ? displayProps[i].displayName : "",
displayProps[i].physicalDimensions.width,
displayProps[i].physicalDimensions.height,
displayProps[i].physicalResolution.width,
displayProps[i].physicalResolution.height,
modesStr);
Jim_ListAppendElement(interp, allDisplaysList, displayDict);
}
}
vkDestroyInstance(instance, NULL);
return allDisplaysList;
}
set displayLib [$cc compile]
if {![catch {exec pkg-config --exists glfw3}]} {
Claim $::thisNode has display glfw with info {name "GLFW (windowed)"}
}
try {
foreach display [$displayLib enumerateDisplays] {
Claim $::thisNode has display $display(name) with info $display
}
} finally {
Claim $::thisNode has had displays enumerated
}
}
<unknown> claims builtin-programs/gpu/pipelines.folk has program code #\ pipelines.folk\ --\n#\n#\ \ (
[ m151:0 (s229:0) ]
)<unknown> claims builtin-programs/gpu/pipelines.folk has program code #\ pipelines.folk\ --\n#\n#\ \ \ \ \ Shared\ render\ pass,\ pipeline\ creation,\ and\ shader\ compilation.\n#\ \ \ \ \ Created\ once\ (not\ per-display).\ Pipelines\ use\ dynamic\ viewport/scissor\n#\ \ \ \ \ so\ they\ work\ across\ displays\ of\ different\ sizes.\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$imageLib\n\$cc\ extend\ -noprocs\ \$gpuTextureLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\}\n\n\$cc\ define\ \{\n\ \ \ \ VkRenderPass\ renderPass\;\n\}\n\n#\ Shader\ compilation:\ndefineVulkanHandleType\ \$cc\ VkShaderModule\n\$cc\ proc\ createShaderModule\ \{Jim_Obj*\ codeObj\}\ VkShaderModule\ \{\n\ \ \ \ int\ codeObjc\ =\ Jim_ListLength(interp,\ codeObj)\;\n\ \ \ \ uint32_t*\ code\ =\ malloc(codeObjc\ *\ sizeof(uint32_t))\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ codeObjc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ Jim_Obj*\ codeObjv\ =\ Jim_ListGetIndex(interp,\ codeObj,\ i)\;\n\ \ \ \ \ \ \ \ long\ val\;\n\ \ \ \ \ \ \ \ Jim_GetLong(interp,\ codeObjv,\ &val)\;\n\ \ \ \ \ \ \ \ code\[i\]\ =\ (uint32_t)val\;\n\ \ \ \ \}\n\n\ \ \ \ VkShaderModuleCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO\;\n\ \ \ \ createInfo.codeSize\ =\ codeObjc\ *\ sizeof(uint32_t)\;\n\ \ \ \ createInfo.pCode\ =\ code\;\n\n\ \ \ \ VkShaderModule\ shaderModule\;\n\ \ \ \ \$\[vktry\ \{vkCreateShaderModule(device,\ &createInfo,\ NULL,\ &shaderModule)\}\]\n\ \ \ \ free(code)\;\n\ \ \ \ return\ shaderModule\;\n\}\n\n#\ Pipeline\ creation:\ndefineVulkanHandleType\ \$cc\ VkPipeline\ndefineVulkanHandleType\ \$cc\ VkPipelineLayout\ndefineVulkanHandleType\ \$cc\ VkDescriptorSet\n\$cc\ typedef\ uint64_t\ VkDeviceSize\n\$cc\ argtype\ VkDescriptorType\ \{\ int\ \$argname\;\ __ENSURE_OK(Tcl_GetIntFromObj(interp,\ \$obj,\ &\$argname))\;\ \}\n\$cc\ rtype\ VkDescriptorType\ \{\ \$robj\ =\ Tcl_NewIntObj(\$rvalue)\;\ \}\n\n\$cc\ code\ \{\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\}\ :extend\ \;#\ needs\ to\ be\ available\ for\ an\ extender\ in\ order\ for\n\ \ \ \ \ \ \ \ \ \ \ #\ Pipeline\ to\ be\ defined.\n\$cc\ struct\ Pipeline\ \{\n\ \ \ \ VkPipeline\ pipeline\;\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\n\n\ \ \ \ size_t\ pushConstantsSize\;\n\ \ \ \ PushConstantsEncoder*\ encodePushConstants\;\n\}\n\n\$cc\ proc\ createPipeline\ \{VkShaderModule\ vertShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkShaderModule\ fragShaderModule\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encodePushConstants\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ size_t\ pushConstantsSize\}\ Pipeline\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ shaderStages\[2\]\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ vertShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.stage\ =\ VK_SHADER_STAGE_VERTEX_BIT\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.module\ =\ vertShaderModule\;\n\ \ \ \ \ \ \ \ vertShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ VkPipelineShaderStageCreateInfo\ fragShaderStageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.stage\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.module\ =\ fragShaderModule\;\n\ \ \ \ \ \ \ \ fragShaderStageInfo.pName\ =\ \"main\"\;\n\n\ \ \ \ \ \ \ \ shaderStages\[0\]\ =\ vertShaderStageInfo\;\n\ \ \ \ \ \ \ \ shaderStages\[1\]\ =\ fragShaderStageInfo\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineVertexInputStateCreateInfo\ vertexInputInfo\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ vertexInputInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexBindingDescriptionCount\ =\ 0\;\n\ \ \ \ \ \ \ \ vertexInputInfo.vertexAttributeDescriptionCount\ =\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ VkPipelineInputAssemblyStateCreateInfo\ inputAssembly\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ inputAssembly.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ inputAssembly.topology\ =\ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST\;\n\ \ \ \ \ \ \ \ inputAssembly.primitiveRestartEnable\ =\ VK_FALSE\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Dummy\ viewport/scissor\ —\ overridden\ by\ dynamic\ state\ at\ draw\ time.\n\ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ viewport.width\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.height\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \}\n\ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ scissor.extent\ =\ (VkExtent2D)\ \{1,\ 1\}\;\n\ \ \ \ \}\n\ \ \ \ VkPipelineViewportStateCreateInfo\ viewportState\ =\ \{0\}\;\n\ \ \ \ viewportState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO\;\n\ \ \ \ viewportState.viewportCount\ =\ 1\;\n\ \ \ \ viewportState.pViewports\ =\ &viewport\;\n\ \ \ \ viewportState.scissorCount\ =\ 1\;\n\ \ \ \ viewportState.pScissors\ =\ &scissor\;\n\n\ \ \ \ VkPipelineRasterizationStateCreateInfo\ rasterizer\ =\ \{0\}\;\n\ \ \ \ rasterizer.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO\;\n\ \ \ \ rasterizer.depthClampEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.rasterizerDiscardEnable\ =\ VK_FALSE\;\n\ \ \ \ rasterizer.polygonMode\ =\ VK_POLYGON_MODE_FILL\;\n\ \ \ \ rasterizer.lineWidth\ =\ 1.0f\;\n\ \ \ \ rasterizer.cullMode\ =\ VK_CULL_MODE_BACK_BIT\;\n\ \ \ \ rasterizer.frontFace\ =\ VK_FRONT_FACE_CLOCKWISE\;\n\ \ \ \ rasterizer.depthBiasEnable\ =\ VK_FALSE\;\n\n\ \ \ \ VkPipelineMultisampleStateCreateInfo\ multisampling\ =\ \{0\}\;\n\ \ \ \ multisampling.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO\;\n\ \ \ \ multisampling.sampleShadingEnable\ =\ VK_FALSE\;\n\ \ \ \ multisampling.rasterizationSamples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\n\ \ \ \ VkPipelineColorBlendAttachmentState\ colorBlendAttachment\ =\ \{0\}\;\n\ \ \ \ colorBlendAttachment.colorWriteMask\ =\n\ \ \ \ \ \ VK_COLOR_COMPONENT_R_BIT\ |\ VK_COLOR_COMPONENT_G_BIT\ |\ VK_COLOR_COMPONENT_B_BIT\ |\n\ \ \ \ \ \ VK_COLOR_COMPONENT_A_BIT\;\n\ \ \ \ colorBlendAttachment.blendEnable\ =\ VK_TRUE\;\n\ \ \ \ colorBlendAttachment.srcColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstColorBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.colorBlendOp\ =\ VK_BLEND_OP_ADD\;\n\ \ \ \ colorBlendAttachment.srcAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE\;\n\ \ \ \ colorBlendAttachment.dstAlphaBlendFactor\ =\ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA\;\n\ \ \ \ colorBlendAttachment.alphaBlendOp\ =\ VK_BLEND_OP_ADD\;\n\n\ \ \ \ VkPipelineColorBlendStateCreateInfo\ colorBlending\ =\ \{0\}\;\n\ \ \ \ colorBlending.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO\;\n\ \ \ \ colorBlending.logicOpEnable\ =\ VK_FALSE\;\n\ \ \ \ colorBlending.logicOp\ =\ VK_LOGIC_OP_COPY\;\n\ \ \ \ colorBlending.attachmentCount\ =\ 1\;\n\ \ \ \ colorBlending.pAttachments\ =\ &colorBlendAttachment\;\n\n\ \ \ \ VkPipelineDynamicStateCreateInfo\ dynamicState\ =\ \{0\}\;\n\ \ \ \ dynamicState.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO\;\n\ \ \ \ dynamicState.dynamicStateCount\ =\ 2\;\n\ \ \ \ VkDynamicState\ dynamicStates\[\]\ =\ \{\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_VIEWPORT,\n\ \ \ \ \ \ \ \ VK_DYNAMIC_STATE_SCISSOR\n\ \ \ \ \}\;\n\ \ \ \ dynamicState.pDynamicStates\ =\ dynamicStates\;\n\n\ \ \ \ VkPipelineLayout\ pipelineLayout\;\ \{\n\ \ \ \ \ \ \ \ VkPipelineLayoutCreateInfo\ pipelineLayoutInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.sType\ =\ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.setLayoutCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ //\ We\ configure\ all\ pipelines\ with\ push\ constants\ size\ =\n\ \ \ \ \ \ \ \ //\ 128\ (the\ maximum),\ no\ matter\ what\ actual\ push\ constants\n\ \ \ \ \ \ \ \ //\ they\ take\;\ this\ is\ so\ that\ pipelines\ are\ all\n\ \ \ \ \ \ \ \ //\ layout-compatible\ so\ we\ can\ reuse\ descriptor\ set\n\ \ \ \ \ \ \ \ //\ between\ pipelines\ without\ needing\ to\ rebind\ it.\n\ \ \ \ \ \ \ \ VkPushConstantRange\ pushConstantRange\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pushConstantRange.offset\ =\ 0\;\n\ \ \ \ \ \ \ \ pushConstantRange.size\ =\ 128\;\n\ \ \ \ \ \ \ \ pushConstantRange.stageFlags\ =\ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pPushConstantRanges\ =\ &pushConstantRange\;\n\ \ \ \ \ \ \ \ pipelineLayoutInfo.pushConstantRangeCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreatePipelineLayout(device,\ &pipelineLayoutInfo,\ NULL,\ &pipelineLayout)\}\]\n\ \ \ \ \}\n\n\ \ \ \ VkPipeline\ pipeline\;\ \{\n\ \ \ \ \ \ \ \ VkGraphicsPipelineCreateInfo\ pipelineInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ pipelineInfo.sType\ =\ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ pipelineInfo.stageCount\ =\ 2\;\n\ \ \ \ \ \ \ \ pipelineInfo.pStages\ =\ shaderStages\;\n\ \ \ \ \ \ \ \ pipelineInfo.pVertexInputState\ =\ &vertexInputInfo\;\n\ \ \ \ \ \ \ \ pipelineInfo.pInputAssemblyState\ =\ &inputAssembly\;\n\ \ \ \ \ \ \ \ pipelineInfo.pViewportState\ =\ &viewportState\;\n\ \ \ \ \ \ \ \ pipelineInfo.pRasterizationState\ =\ &rasterizer\;\n\ \ \ \ \ \ \ \ pipelineInfo.pMultisampleState\ =\ &multisampling\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDepthStencilState\ =\ NULL\;\n\ \ \ \ \ \ \ \ pipelineInfo.pColorBlendState\ =\ &colorBlending\;\n\ \ \ \ \ \ \ \ pipelineInfo.pDynamicState\ =\ &dynamicState\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.layout\ =\ pipelineLayout\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ pipelineInfo.subpass\ =\ 0\;\n\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineHandle\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ pipelineInfo.basePipelineIndex\ =\ -1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateGraphicsPipelines(device,\ VK_NULL_HANDLE,\ 1,\ &pipelineInfo,\ NULL,\ &pipeline)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ (Pipeline)\ \{\n\ \ \ \ \ \ \ \ .pipeline\ =\ pipeline,\n\ \ \ \ \ \ \ \ .pipelineLayout\ =\ pipelineLayout,\n\ \ \ \ \ \ \ \ .pushConstantsSize\ =\ pushConstantsSize,\n\ \ \ \ \ \ \ \ .encodePushConstants\ =\ encodePushConstants\n\ \ \ \ \}\;\n\}\n\n#\ Bind\ the\ shared\ texture\ descriptor\ set\ on\ a\ command\ buffer.\n\$cc\ proc\ bindTextureDescriptorSet\ \{VkCommandBuffer\ commandBuffer\ VkPipelineLayout\ pipelineLayout\}\ void\ \{\n\ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\}\n\$cc\ proc\ getTextureDescriptorSet\ \{\}\ VkDescriptorSet\ \{\n\ \ \ \ return\ *textureDescriptorSet_ptr()\;\n\}\n\n\$cc\ proc\ pipelinesInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachment.format\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR\;\n\n\ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \}\n\}\n\nset\ pipelineLib\ \[\$cc\ compile\]\n\$pipelineLib\ pipelinesInit\nClaim\ the\ GPU\ pipeline\ library\ is\ \$pipelineLib\n\n#\ Pipeline\ compiler:\ Tcl-level\ library\ that\ takes\ GLSL\ fragments,\n#\ routes\ them\ through\ glslc,\ builds\ a\ C\ subcompiler\ for\ push-constant\n#\ encoding,\ and\ produces\ a\ Pipeline\ via\ createPipeline\ above.\nset\ pipelineCompilerLib\ \[library\ create\ pipelineCompiler\ \{gpuLib\ pipelineLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\n\ \ \ \ #\ Construct\ a\ reusable\ GLSL\ function\ that\ can\ be\ linked\ into\ and\n\ \ \ \ #\ called\ from\ a\ shader/pipeline.\n\ \ \ \ proc\ fn\ \{fnDict\ arguments\ rtype\ body\}\ \{\n\ \ \ \ \ \ \ \ set\ fnArgs\ \[list\]\n\ \ \ \ \ \ \ \ #\ We\ inline\ all\ dependent\ functions\ from\ the\ caller\ scope\n\ \ \ \ \ \ \ \ #\ immediately\ here,\ since\ we\ don't\ know\ if\ those\ dependencies\n\ \ \ \ \ \ \ \ #\ would\ be\ accessible/in\ scope\ at\ all\ when\ this\ function\ gets\n\ \ \ \ \ \ \ \ #\ actually\ compiled\ into\ a\ shader.\n\ \ \ \ \ \ \ \ set\ depFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$arguments\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{fnName\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"pipelineCompiler::fn:\ \$argname\ not\ found\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ depFnDict\ \[string\ map\ \{:\ \"\"\}\ \$argname\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ fnArgs\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \[list\ \$fnArgs\ \$depFnDict\ \$rtype\ \$body\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Construct\ a\ shader\ pipeline\ that\ can\ be\ used\ to\ draw\ to\ the\n\ \ \ \ #\ screen.\n\ \ \ \ proc\ pipeline\ \{fnDict\ args\}\ \{\n\ \ \ \ \ \ \ \ variable\ gpuLib\n\ \ \ \ \ \ \ \ variable\ pipelineLib\n\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 3\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fragArgs\ \[list\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$args\]\ ==\ 4\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$args\ vertArgs\ vertBody\ fragArgs\ fragBody\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \{pipelineCompiler\ pipeline:\ should\ be\ used\ as\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragBody\],\ or\ \[\$pipelineCompiler\ pipeline\ vertArgs\ vertBody\ fragArgs\ fragBody\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ create\]\n\ \ \ \ \ \ \ \ set\ pushConstants\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$vertArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vertFnDict\ \[dict\ merge\ \$vertFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ vertFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ pushConstants\ \$argtype\ \$argname\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ \{argtype\ argname\}\ \$fragArgs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"fn\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Support\ fn\ being\ a\ list\ \{name\ fn\}.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$fnDict\ \$argname\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ 99\ \$argname\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fn\ \[dict\ get\ \$fnDict\ \$argname\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fragFnDict\ \[dict\ merge\ \$fragFnDict\ \[lindex\ \$fn\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ fragFnDict\ \$argname\ \$fn\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"Fragment\ arguments\ not\ supported\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Create\ a\ C\ subcompiler\ to\ create\ a\ fast\ routine\ to\ encode\n\ \ \ \ \ \ \ \ #\ the\ push\ constants\ on\ each\ draw\ call.\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ typedef\ int\ sampler2D\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec2\ \{\ float\ x\;\ float\ y\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec3\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ vec4\ \{\ float\ x\;\ float\ y\;\ float\ z\;\ float\ w\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ struct\ uvec4\ \{\ uint32_t\ x\;\ uint32_t\ y\;\ uint32_t\ z\;\ uint32_t\ w\;\ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ mat3\ is\ COLUMN-MAJOR\ and\ every\ column\ has\ 1\ float\n\ \ \ \ \ \ \ \ #\ of\ padding\ at\ the\ end.\n\ \ \ \ \ \ \ \ \$cc\ struct\ mat3\ \{\ float\ data\[12\]\;\ \}\n\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec2\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 2)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec2)\ \{\ (float)x,\ (float)y\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec3)\ \{\ (float)x,\ (float)y,\ (float)z\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ vec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ x\;\ double\ y\;\ double\ z\;\ double\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (vec4)\ \{\ (float)x,\ (float)y,\ (float)z,\ (float)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ argtype\ uvec4\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uvec4\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ jim_wide\ x\;\ jim_wide\ y\;\ jim_wide\ z\;\ jim_wide\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 0),\ &x))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 1),\ &y))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 2),\ &z))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetWide(interp,\ Jim_ListGetIndex(interp,\ \$obj,\ 3),\ &w))\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname\ =\ (uvec4)\ \{\ (uint32_t)x,\ (uint32_t)y,\ (uint32_t)z,\ (uint32_t)w\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ take\ matrices\ from\ Tcl\ in\ ROW-MAJOR\ form\ and\n\ \ \ \ \ \ \ \ #\ convert\ them\ to\ column-major\ form\ inline\ here.\n\ \ \ \ \ \ \ \ \$cc\ argtype\ mat3\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mat3\ \$argname\;\n\ \ \ \ \ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ \$\[set\ argname\]_objc\ =\ Jim_ListLength(interp,\ \$obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(\$\[set\ argname\]_objc\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ 3\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ rowObj\ =\ Jim_ListGetIndex(interp,\ \$obj,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE(Jim_ListLength(interp,\ rowObj)\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ 3\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ __ENSURE_OK(Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ rowObj,\ x),\ &el))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ x\ *\ 4\ +\ y\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$argname.data\[i\]\ =\ el\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ code\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ alignas\ \[expr\ \{\$argtype\ eq\ \"mat3\"\ ?\ \"16\"\ :\ \"sizeof(\$argtype)\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{_Alignas(\$alignas)\ \$argtype\ \$argname\;\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ Args\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ static\ uint8_t\ argsBuf\[128\]\;\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \$cc\ include\ <stddef.h>\n\ \ \ \ \ \ \ \ \$cc\ proc\ getArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeArgs\ \$pushConstants\ void\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Args\ args\ =\ \{\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\ subst\ \{.\$argname\ =\ \$argname\}\ \}\]\ \"\ ,\"\]\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(argsBuf,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ This\ is\ what\ gets\ saved\ as\ the\ PushConstantsEncoder\ and\n\ \ \ \ \ \ \ \ #\ called\ at\ draw\ time.\n\ \ \ \ \ \ \ \ \$cc\ proc\ encodeObj\ \{Jim_Interp*\ interp\ Jim_Obj*\ obj\ uint8_t*\ out\}\ int\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ objc\ =\ Jim_ListLength(interp,\ obj)\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ objv\[1\ +\ objc\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ objc\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ objv\[1\ +\ i\]\ =\ Jim_ListGetIndex(interp,\ obj,\ i)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ encodeArgs_Cmd(interp,\ 1\ +\ objc,\ objv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ !=\ JIM_OK)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ You\ CANNOT\ use\ FOLK_ENSURE\ here,\ because\ this\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ passed\ as\ function\ pointer\ and\ does\ not\ capture\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ correct\ jmp_buf\ for\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(out,\ argsBuf,\ sizeof(Args))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ sizeof(Args)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ makeEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ PushConstantsEncoder*\ encoder\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ \ \ \ \ \ \ \ \ encoder->encode\ =\ encodeObj\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ encoder\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ encoderLib\ \[\$cc\ compile\]\n\n\ \ \ \ \ \ \ \ set\ encodePushConstants\ \[\$encoderLib\ makeEncoder\]\n\ \ \ \ \ \ \ \ set\ pushConstantsSize\ \[\$encoderLib\ getArgsSize\]\n\n\ \ \ \ \ \ \ \ set\ pushConstantsCode\ \[if\ \{\[llength\ \$pushConstants\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"int\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ args\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=vert\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$vertFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ vert()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\ =\ args.\$argname\;\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\ \"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vert()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\ \ \ \ \ \ \ \ #\ We\ pass\ the\ descriptor\ set\ with\ all\ textures\ (samplers)\ to\ all\n\ \ \ \ \ \ \ \ #\ fragment\ shaders,\ so\ we\ never\ need\ to\ rebind\ it\ (at\ draw\n\ \ \ \ \ \ \ \ #\ time,\ the\ shader\ may\ get\ an\ index\ into\ the\ array\ if\ it's\n\ \ \ \ \ \ \ \ #\ meant\ to\ draw\ an\ texture).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Note\ that\ we\ have\ individual\ combined\ image+samplers,\n\ \ \ \ \ \ \ \ #\ instead\ of\ 1\ global\ sampler\ and\ multiple\ images/textures,\n\ \ \ \ \ \ \ \ #\ because\ that's\ the\ only\ way\ to\ allow\ each\ texture\ to\ have\n\ \ \ \ \ \ \ \ #\ its\ own\ dimensions\ (dimensions\ are\ a\ property\ bound\ to\ the\n\ \ \ \ \ \ \ \ #\ sampler).\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ We\ have\ a\ whole\ code\ path\ basically\ just\ to\ handle\ v3dv\n\ \ \ \ \ \ \ \ #\ (Raspberry\ Pi\ GPU),\ which\ doesn't\ support\ dynamic\ indexing\n\ \ \ \ \ \ \ \ #\ (based\ on\ push\ constant)\ into\ the\ descriptor\ array.\ On\ GPUs\n\ \ \ \ \ \ \ \ #\ like\ that,\ we\ manually\ emit\ an\ if\ ladder\ that\ checks\ each\n\ \ \ \ \ \ \ \ #\ possible\ value\ of\ the\ push\ constant\ and\ uses\ the\ right\n\ \ \ \ \ \ \ \ #\ statically-indexed\ descriptor.\n\ \ \ \ \ \ \ \ set\ gpuSupportsDynamicIndexing\ \[\$gpuLib\ getDoesSupportShaderSampledImageArrayDynamicIndexing\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[glslc\ -fshader-stage=frag\ \[csubst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(set\ =\ 0,\ binding\ =\ 0)\ uniform\ sampler2D\ _samplers\[\$\[\$gpuLib\ getMaxTextures\]\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsCode\n\n\ \ \ \ \ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[join\ \[lmap\ \{fnName\ fn\}\ \$fragFnDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ fnArgs\ _\ fnRtype\ fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnRtype\ \$fnName\ (\[join\ \[lmap\ \{fnArgtype\ fnArgname\}\ \$fnArgs\ \{subst\ \{\$fnArgtype\ \$fnArgname\}\}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fnBody\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ frag(\$\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argtype\ \$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$fragBody\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[eval\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdxs\ \[lsearch\ -all\ -exact\ \$pushConstants\ sampler2D\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ proc\ emitFragInvocation\ \{gpuSupportsDynamicIndexing\ pushConstants\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ rawColor\ =\ frag(\[join\ \[lmap\ \{argtype\ argname\}\ \$pushConstants\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argname\ eq\ \"_\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$argtype\ eq\ \"sampler2D\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$gpuSupportsDynamicIndexing\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"_samplers\\\[args.\$argname\\\]\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ This\ should\ have\ been\ patched\ to\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ static\ expression\ like\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ `_samplers\[3\]`\ by\ the\ caller.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\"args.\$argname\"\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \",\ \"\])\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Premultiply\ the\ RGB\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(rawColor.rgb\ *\ rawColor.a,\ rawColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\[if\ \{\$gpuSupportsDynamicIndexing\ ||\ \[llength\ \$samplerIdxs\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$pushConstants\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[llength\ \$samplerIdxs\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerIdx\ \[+\ \[lindex\ \$samplerIdxs\ 0\]\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ samplerName\ \[lindex\ \$pushConstants\ \$samplerIdx\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxTextures\ \[\$gpuLib\ getMaxTextures\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ xs\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$maxTextures\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ patchedPushConstants\ \[lreplace\ \$pushConstants\ \$samplerIdx\ \$samplerIdx\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _samplers\\\[\$i\\\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ xs\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$i\ ==\ 0\ ?\ \"if\"\ :\ \"else\ if\"\}\]\ (args.\$samplerName\ ==\ \$i)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[emitFragInvocation\ \$gpuSupportsDynamicIndexing\ \$patchedPushConstants\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ join\ \$xs\ \"\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ error\ \"display:\ Cannot\ currently\ compile\ a\ shader\ that\ has\ more\ than\ 1\ sampler2D\ parameter\ on\ this\ GPU.\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\]\]\n\n\ \ \ \ \ \ \ \ #\ pipeline\ needs\ to\ contain\ a\ specification\ of\ push\ constants,\n\ \ \ \ \ \ \ \ #\ so\ they\ can\ be\ filled\ in\ at\ draw\ time.\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$encodePushConstants\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$pushConstantsSize\]\n\ \ \ \ \ \ \ \ return\ \$pipeline\n\ \ \ \ \}\n\n\ \ \ \ proc\ glslc\ \{args\}\ \{\n\ \ \ \ \ \ \ \ set\ cmdargs\ \[lreplace\ \$args\ end\ end\]\n\ \ \ \ \ \ \ \ set\ glsl\ \[lindex\ \$args\ end\]\n\ \ \ \ \ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/glslfileXXXXXX\].glsl\n\ \ \ \ \ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ \ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ \{*\}\$cmdargs\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\ \ \ \ \}\n\}\]\nClaim\ the\ GPU\ pipeline\ compiler\ library\ is\ \$pipelineCompilerLib\n\n\}\n
<unknown> claims builtin-programs/gpu/textures.folk has program code When\ the\ GPU\ Vulkan\ handle\ (
[ m153:0 (s234:0) ]
)<unknown> claims builtin-programs/gpu/textures.folk has program code When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ VMA\ DLL\ is\ /vmaDll/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ \{\n\nfn\ defineVulkanHandleType\n\nset\ gpuc\ \[C\]\n\$gpuc\ cflags\ -I./vendor\n\$gpuc\ endcflags\ \$vmaDll\n\$gpuc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ void\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\;\n\ \ \ \ VmaAllocator\ vmaGetAllocator()\;\n\}\n\$gpuc\ include\ <pthread.h>\n\$gpuc\ include\ <stdlib.h>\n\$gpuc\ include\ <string.h>\n\$gpuc\ include\ <stdatomic.h>\n\n\$gpuc\ extend\ \$gpuLib\n\$gpuc\ extend\ \$imageLib\n\n\$gpuc\ include\ <pthread.h>\n\n\$gpuc\ typedef\ \{struct\ VmaAllocation_T*\}\ VmaAllocation\n\$gpuc\ argtype\ VmaAllocation\ \{\n\ \ \ \ VmaAllocation\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(VmaAllocation)\ %p\",\ &\$argname)\;\n\}\n\$gpuc\ rtype\ VmaAllocation\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(VmaAllocation)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n#\ Texture\ management:\n\n#\ The\ technique\ used\ to\ manage\ textures\ here\ is\ to\ have\ a\n#\ single\ giant\ descriptor\ set\ for\ a\ giant\ GPU-side\ array\ of\n#\ textures,\ which\ all\ shaders\ can\ access.\ (That\ descriptor\ set\n#\ _never_\ has\ to\ be\ rebound\;\ it\ stays\ bound\ through\ all\ draw\n#\ calls,\ forever.)\n#\ \n#\ Each\ texture\ has\ to\ be\ 'copied\ to\ the\ GPU'\ before\ you\ do\ any\n#\ draw\ calls\ that\ use\ it.\ Copying\ an\ texture\ to\ the\ GPU\ gives\n#\ you\ a\ GPU-side\ texture\ handle,\ which\ is\ just\ an\ integer\ index\n#\ into\ the\ GPU-side\ array.\ You\ can\ pass\ that\ texture\ handle\n#\ into\ draw\ calls\ as\ a\ parameter\ (push\ constant)\ when\ you\n#\ want\ to\ draw/use\ the\ texture.\n#\n#\ See:\n#\ -\ http://kylehalladay.com/blog/tutorial/vulkan/2018/01/28/Textue-Arrays-Vulkan.html\n#\ -\ https://chunkstories.xyz/blog/a-note-on-descriptor-indexing/\n#\ -\ https://gist.github.com/DethRaid/0171f3cfcce51950ee4ef96c64f59617\n#\ -\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\$gpuc\ define\ \{\n\ \ \ \ VkDescriptorSetLayout\ textureDescriptorSetLayout\;\n\ \ \ \ VkDescriptorSet\ textureDescriptorSet\;\n\}\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSetLayout\ndefineVulkanHandleType\ \$gpuc\ VkDescriptorSet\n\n\$gpuc\ code\ \{\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ static\ void\ initPlaceholderTexture()\;\n\}\n\n\$gpuc\ typedef\ int\ GpuTextureHandle\ndefineVulkanHandleType\ \$gpuc\ VkImage\ndefineVulkanHandleType\ \$gpuc\ VkDeviceMemory\ndefineVulkanHandleType\ \$gpuc\ VkImageView\ndefineVulkanHandleType\ \$gpuc\ VkSampler\n\$gpuc\ struct\ GpuTextureBlock\ \{\n\ \ \ \ bool\ _Atomic\ alive\;\n\ \ \ \ bool\ _Atomic\ retiring\;\n\n\ \ \ \ int\ width\;\n\ \ \ \ int\ height\;\n\ \ \ \ int\ retireAfterFrame\;\n\n\ \ \ \ GpuTextureHandle\ handle\;\n\n\ \ \ \ VkImage\ textureImage\;\n\ \ \ \ VmaAllocation\ textureImageAllocation\;\n\ \ \ \ VkImageView\ textureImageView\;\n\ \ \ \ VkSampler\ textureSampler\;\n\n\ \ \ \ //\ mostly\ for\ debugging:\n\ \ \ \ char*\ description\;\n\}\n\$gpuc\ code\ \{\n\ \ \ \ //\ Array\ of\ GpuTextureBlocks.\ Each\ element\ points\ to\ all\ GPU-side\n\ \ \ \ //\ data\ structures\ associated\ with\ a\ particular\ texture\ (that\ we\n\ \ \ \ //\ will\ destroy\ when\ we\ evict\ that\ texture).\n\ \ \ \ struct\ GpuTextureBlock*\ gpuTextures\;\n\n\ \ \ \ //\ Deferred\ descriptor-set\ updates\ and\ resource\ destruction,\n\ \ \ \ //\ drained\ once\ per\ frame\ on\ the\ GPU\ thread\ when\ the\ GPU\ is\ idle.\n\ \ \ \ enum\ DeferredTextureOp\ \{\ DEFERRED_ADD,\ DEFERRED_FREE\ \}\;\n\ \ \ \ struct\ DeferredTextureEntry\ \{\n\ \ \ \ \ \ \ \ enum\ DeferredTextureOp\ op\;\n\ \ \ \ \ \ \ \ GpuTextureHandle\ handle\;\n\ \ \ \ \}\;\n\ \ \ \ #define\ DEFERRED_QUEUE_CAP\ 256\n\ \ \ \ struct\ DeferredTextureEntry\ deferredQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ int\ _Atomic\ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_t\ deferredQueueMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\ \ \ \ #define\ TEXTURE_RETIRE_GRACE_FRAMES\ 2\n\ \ \ \ int\ textureFrameEpoch\ =\ 0\;\n\}\n\$gpuc\ proc\ textureManagerInit\ \{\}\ void\ \{\n\ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ gpuTextures\ =\ calloc(sizeof(GpuTextureBlock),\ getMaxTextures())\;\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSetLayout:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ /*\ VkDescriptorBindingFlags\ flags\[1\]\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT\;\ */\n\ \ \ \ \ \ \ \ /*\ flags\[0\]\ =\ VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT\;\ */\n\n\ \ \ \ \ \ \ \ /*\ VkDescriptorSetLayoutBindingFlagsCreateInfo\ bindingFlags\ =\ \{0\}\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.bindingCount\ =\ 1\;\ */\n\ \ \ \ \ \ \ \ /*\ bindingFlags.pBindingFlags\ =\ flags\;\ */\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutBinding\ bindings\[1\]\;\n\ \ \ \ \ \ \ \ memset(bindings,\ 0,\ sizeof(bindings))\;\n\ \ \ \ \ \ \ \ bindings\[0\].binding\ =\ 0\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ bindings\[0\].descriptorCount\ =\ getMaxTextures()\;\n\ \ \ \ \ \ \ \ bindings\[0\].stageFlags\ =\ VK_SHADER_STAGE_FRAGMENT_BIT\;\n\n\ \ \ \ \ \ \ \ VkDescriptorSetLayoutCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO\;\n\ \ \ \ \ \ \ \ createInfo.bindingCount\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.pBindings\ =\ bindings\;\n\ \ \ \ \ \ \ \ /*\ createInfo.pNext\ =\ &bindingFlags\;\ */\n\n\ \ \ \ \ \ \ \ vkCreateDescriptorSetLayout(device,\ &createInfo,\ NULL,\ textureDescriptorSetLayout_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorPool\ descriptorPool\;\ \{\n\ \ \ \ \ \ \ \ VkDescriptorPoolSize\ poolSize\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolSize.type\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ poolSize.descriptorCount\ =\ 512\;\n\n\ \ \ \ \ \ \ \ VkDescriptorPoolCreateInfo\ poolInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ poolInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO\;\n\ \ \ \ \ \ \ \ poolInfo.poolSizeCount\ =\ 1\;\n\ \ \ \ \ \ \ \ poolInfo.pPoolSizes\ =\ &poolSize\;\n\ \ \ \ \ \ \ \ poolInfo.maxSets\ =\ 100\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDescriptorPool(device,\ &poolInfo,\ NULL,\ &descriptorPool)\}\]\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ textureDescriptorSet:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkDescriptorSetAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorPool\ =\ descriptorPool\;\n\ \ \ \ \ \ \ \ allocInfo.descriptorSetCount\ =\ 1\;\n\ \ \ \ \ \ \ \ allocInfo.pSetLayouts\ =\ textureDescriptorSetLayout_ptr()\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkAllocateDescriptorSets(device,\ &allocInfo,\ textureDescriptorSet_ptr())\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Initialize\ VMA\ allocator\n\ \ \ \ vmaInit(*instance_ptr(),\ *physicalDevice_ptr(),\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties)\;\n\n\ \ \ \ initPlaceholderTexture()\;\n\}\n\n#\ Buffer\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ uint32_t\ findMemoryType(uint32_t\ typeFilter,\ VkMemoryPropertyFlags\ properties)\ \{\n\ \ \ \ \ \ \ \ VkPhysicalDeviceMemoryProperties\ memProperties\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceMemoryProperties(*physicalDevice_ptr(),\ &memProperties)\;\n\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ memProperties.memoryTypeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((typeFilter\ &\ (1\ <<\ i))\ &&\ (memProperties.memoryTypes\[i\].propertyFlags\ &\ properties)\ ==\ properties)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ typedef\ size_t\ VkDeviceSize\ false\n\$gpuc\ typedef\ uint32_t\ VkBufferUsageFlags\ false\n\$gpuc\ typedef\ uint32_t\ VkMemoryPropertyFlags\ false\n\$gpuc\ proc\ createBuffer\ \{VkDeviceSize\ size\ VkBufferUsageFlags\ usage\ VkMemoryPropertyFlags\ properties\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkBuffer*\ buffer\ VmaAllocation*\ allocation\}\ void\ \{\n\ \ \ \ VkBufferCreateInfo\ bufferInfo\ =\ \{0\}\;\n\ \ \ \ bufferInfo.sType\ =\ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO\;\n\ \ \ \ bufferInfo.size\ =\ size\;\n\ \ \ \ bufferInfo.usage\ =\ usage\;\n\ \ \ \ bufferInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \}\n\ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\ |\ VMA_ALLOCATION_CREATE_MAPPED_BIT\;\n\ \ \ \ \}\n\n\ \ \ \ VkResult\ res\ =\ vmaCreateBuffer(vmaGetAllocator(),\ &bufferInfo,\ &allocInfo,\ buffer,\ allocation,\ NULL)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ buffer\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\}\n\n#\ Texture\ allocation:\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ void\ createImage(uint32_t\ width,\ uint32_t\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkFormat\ format,\ VkImageTiling\ tiling,\ VkImageUsageFlags\ usage,\ VkMemoryPropertyFlags\ properties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImage*\ image,\ VmaAllocation*\ allocation)\ \{\n\ \ \ \ \ \ \ \ VkImageCreateInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ imageInfo.imageType\ =\ VK_IMAGE_TYPE_2D\;\n\ \ \ \ \ \ \ \ imageInfo.extent.width\ =\ width\;\n\ \ \ \ \ \ \ \ imageInfo.extent.height\ =\ height\;\n\ \ \ \ \ \ \ \ imageInfo.extent.depth\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.mipLevels\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.arrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ imageInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ imageInfo.tiling\ =\ tiling\;\n\ \ \ \ \ \ \ \ //\ TODO:\ this\ means\ it\ can't\ be\ drawn\ right\ away\ (validation\ error).\n\ \ \ \ \ \ \ \ imageInfo.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ imageInfo.usage\ =\ usage\;\n\ \ \ \ \ \ \ \ imageInfo.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ imageInfo.sharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\n\ \ \ \ \ \ \ \ VmaAllocationCreateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ allocInfo.usage\ =\ VMA_MEMORY_USAGE_AUTO\;\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.requiredFlags\ =\ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (properties\ &\ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.flags\ =\ VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ vmaCreateImage(vmaGetAllocator(),\ &imageInfo,\ &allocInfo,\ image,\ allocation,\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ image\ with\ VMA:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ VmaAllocationInfo\ vmaInfo\;\n\ \ \ \ \ \ \ \ vmaGetAllocationInfo(vmaGetAllocator(),\ *allocation,\ &vmaInfo)\;\n\ \ \ \ \ \ \ \ TracyCAlloc(*allocation,\ vmaInfo.size)\;\n#endif\n\ \ \ \ \}\n\}\]\n\ndefineVulkanHandleType\ \$gpuc\ VkCommandBuffer\ndefineVulkanHandleType\ \$gpuc\ VkFence\n\$gpuc\ proc\ beginSingleTimeCommands\ \{\}\ VkCommandBuffer\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\n\ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ return\ commandBuffer\;\n\}\n\$gpuc\ proc\ endSingleTimeCommands\ \{VkCommandBuffer\ commandBuffer\ VkFence\ fence\}\ void\ \{\n\ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ fence)\;\n\ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\}\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ __thread\ VkFence\ _fence\ =\ VK_NULL_HANDLE\;\n\}\n\$gpuc\ proc\ getFence\ \{\}\ VkFence\ \{\n\ \ \ \ if\ (_fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &_fence)\}\]\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &_fence)\;\n\ \ \ \ \}\n\ \ \ \ return\ _fence\;\n\}\n\n\$gpuc\ typedef\ int\ VkFormat\ false\n\$gpuc\ typedef\ int\ VkImageLayout\ false\n\$gpuc\ proc\ transitionImageLayout\ \{VkImage\ image\ VkFormat\ format\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkImageLayout\ oldLayout\ VkImageLayout\ newLayout\}\ void\ \{\n\ \ \ \ VkFence\ fence\ =\ getFence()\;\n\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ beginSingleTimeCommands()\;\n\n\ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ barrier.oldLayout\ =\ oldLayout\;\n\ \ \ \ barrier.newLayout\ =\ newLayout\;\n\ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ barrier.image\ =\ image\;\n\ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\n\ \ \ \ VkPipelineStageFlags\ sourceStage\;\n\ \ \ \ VkPipelineStageFlags\ destinationStage\;\n\ \ \ \ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TRANSFER_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ if\ (oldLayout\ ==\ VK_IMAGE_LAYOUT_UNDEFINED\ &&\ newLayout\ ==\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\ \{\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ sourceStage\ =\ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT\;\n\ \ \ \ \ \ \ \ destinationStage\ =\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ exit(91)\;\n\ \ \ \ \}\n\ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sourceStage,\ destinationStage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ NULL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\ &barrier)\;\n\n\ \ \ \ endSingleTimeCommands(commandBuffer,\ fence)\;\n\ \ \ \ //\ HACK:\ this\ wait\ is\ so\ that\ the\ commandBuffer\ is\ usable\ afterward.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &fence,\ VK_TRUE,\ UINT64_MAX)\;\n\}\n\n#\ Copy\ 1-channel,\ 3-channel,\ or\ 4-channel\ im\ to\ 4-channel\ ret.\n\$gpuc\ proc\ copyImageToRgba\ \{Image\ im\ Image\ ret\}\ void\ \{\n\ \ \ \ FOLK_ENSURE(im.width\ ==\ ret.width\ &&\ im.height\ ==\ ret.height)\;\n\n\ \ \ \ if\ (im.components\ ==\ 4)\ \{\n\ \ \ \ \ \ \ \ if\ (ret.bytesPerRow\ ==\ im.bytesPerRow)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Optimized\ bulk\ copy\ when\ row\ stride\ matches\n\ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data,\ im.data,\ ret.bytesPerRow\ *\ ret.height)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Row-by-row\ copy\ when\ stride\ differs\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(ret.data\ +\ y*ret.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.data\ +\ y*im.bytesPerRow,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ im.width*4)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(im.components\ ==\ 1\ ||\ im.components\ ==\ 3)\;\n\ \ \ \ if\ (im.components\ ==\ 3)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx+0\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx+1\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx+2\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ im.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ im.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ imidx\ =\ y*im.bytesPerRow\ +\ x*im.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ im.data\[imidx\],\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ g\ =\ im.data\[imidx\],\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ b\ =\ im.data\[imidx\]\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ ridx\ =\ y*ret.bytesPerRow\ +\ x*ret.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+0\]\ =\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+1\]\ =\ g\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+2\]\ =\ b\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret.data\[ridx+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n\$gpuc\ code\ \[csubst\ \{\n\ \ \ \ GpuTextureHandle\ allocateGpuTextureHandle()\ \{\n\ \ \ \ \ \ \ \ for\ (\;\;)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bool\ notAlive\ =\ false\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (atomic_compare_exchange_weak(&gpuTextures\[i\].alive,\ ¬Alive,\ true))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gpuTextures\[i\].handle\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Exceeded\ GPU\ max\ textures\ (%d):\\n\",\ getMaxTextures())\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"\ \ %d:\ %s\\n\",\ i,\ gpuTextures\[i\].alive\ ?\ gpuTextures\[i\].description\ :\ \"<not\ alive>\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ struct\ timespec\ ts\ =\ \{0,\ 5000000\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ nanosleep(&ts,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\n\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ enqueueDeferredTextureOp(enum\ DeferredTextureOp\ op,\ GpuTextureHandle\ handle)\ \{\n\ \ \ \ \ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ \ \ \ \ if\ (deferredQueueCount\ >=\ DEFERRED_QUEUE_CAP)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/textures:\ Deferred\ queue\ full\ (%d)\\n\",\ DEFERRED_QUEUE_CAP)\;\n\ \ \ \ \ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ deferredQueue\[deferredQueueCount++\]\ =\ (struct\ DeferredTextureEntry)\{op,\ handle\}\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Write\ a\ single\ texture\ slot\ into\ the\ descriptor\ set.\ Must\ only\n\ \ \ \ //\ be\ called\ on\ the\ GPU\ thread\ between\ frames\ (or\ during\ init).\n\ \ \ \ static\ void\ writeTextureDescriptor(GpuTextureHandle\ textureId)\ \{\n\ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[textureId\].textureImageView\;\n\ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[textureId\].textureSampler\;\n\n\ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ textureId\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ initializeDescriptorSet\ \{GpuTextureHandle\ firstTextureId\}\ void\ \{\n\ \ \ \ //\ Hack:\ if\ we're\ not\ using\ the\ descriptor\ indexing\ extension,\n\ \ \ \ //\ we\ can't\ have\ a\ partially\ bound\ descriptor\ set,\ so\ we\ need\n\ \ \ \ //\ to\ fill\ all\ the\ slots\ in\ the\ texture\ array\ with\ _something_.\n\ \ \ \ //\ We\ just\ fill\ all\ slots\ with\ the\ first\ texture\ for\ now.\ See\n\ \ \ \ //\ http://roar11.com/2019/06/vulkan-textures-unbound/\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[firstTextureId\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[firstTextureId\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrites\[getMaxTextures()\]\;\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ getMaxTextures()\;\ i++)\ \{\n\ \ \ \ \ \ \ \ memset(&descriptorWrites\[i\],\ 0,\ sizeof(VkWriteDescriptorSet))\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].dstArrayElement\ =\ i\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ descriptorWrites\[i\].pImageInfo\ =\ &imageInfo\;\n\ \ \ \ \}\n\ \ \ \ vkUpdateDescriptorSets(device,\ getMaxTextures(),\ descriptorWrites,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ addToTextureDescriptorSet\ \{GpuTextureHandle\ textureId\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_ADD,\ textureId)\;\n\}\n\n\$gpuc\ proc\ getGpuTexture\ \{GpuTextureHandle\ handle\}\ GpuTextureBlock*\ \{\n\ \ \ \ return\ &gpuTextures\[handle\]\;\n\}\n\n#\ NOTE:\ The\ caller\ must\ call\ addToTextureDescriptorSet\ at\ some\ point\n#\ after\ calling\ this\ to\ actually\ use\ the\ texture.\n\$gpuc\ proc\ createGpuTexture\ \{int\ width\ int\ height\ int\ format\}\ GpuTextureBlock*\ \{\n\ \ \ \ GpuTextureHandle\ textureId\ =\ allocateGpuTextureHandle()\;\n\ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[textureId\]\;\n\n\ \ \ \ block->width\ =\ width\;\n\ \ \ \ block->height\ =\ height\;\n\ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ block->retireAfterFrame\ =\ 0\;\n\n\ \ \ \ createImage(width,\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (VkFormat)\ format,\ VK_IMAGE_TILING_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_TRANSFER_DST_BIT\ |\ VK_IMAGE_USAGE_TRANSFER_SRC_BIT\ |\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_USAGE_SAMPLED_BIT\ |\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &block->textureImage,\ &block->textureImageAllocation)\;\n\n\ \ \ \ //\ Set\ up\ block->textureImageView:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkImageViewCreateInfo\ viewInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ viewInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ viewInfo.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ viewInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ viewInfo.format\ =\ format\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ viewInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &viewInfo,\ NULL,\ &block->textureImageView)\}\]\n\ \ \ \ \}\n\ \ \ \ //\ Set\ up\ block->textureSampler:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSamplerCreateInfo\ samplerInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ samplerInfo.sType\ =\ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ samplerInfo.magFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.minFilter\ =\ VK_FILTER_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeU\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeV\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.addressModeW\ =\ VK_SAMPLER_ADDRESS_MODE_REPEAT\;\n\ \ \ \ \ \ \ \ samplerInfo.anisotropyEnable\ =\ VK_FALSE\;\ //\ TODO:\ do\ we\ want\ this?\n\ \ \ \ \ \ \ \ samplerInfo.borderColor\ =\ VK_BORDER_COLOR_INT_OPAQUE_BLACK\;\n\ \ \ \ \ \ \ \ samplerInfo.unnormalizedCoordinates\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareEnable\ =\ VK_FALSE\;\n\ \ \ \ \ \ \ \ samplerInfo.compareOp\ =\ VK_COMPARE_OP_ALWAYS\;\n\ \ \ \ \ \ \ \ samplerInfo.mipmapMode\ =\ VK_SAMPLER_MIPMAP_MODE_LINEAR\;\n\ \ \ \ \ \ \ \ samplerInfo.mipLodBias\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.minLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ samplerInfo.maxLod\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSampler(device,\ &samplerInfo,\ NULL,\ &block->textureSampler)\}\]\n\ \ \ \ \}\n\n\ \ \ \ block->description\ =\ malloc(32)\;\n\ \ \ \ snprintf(block->description,\ 32,\ \"%dx%d\ texture\",\ width,\ height)\;\n\ \ \ \ return\ block\;\n\}\n\n#\ Per-worker\ reusable\ texture\ upload\ slots.\ Staging\ buffers\ stay\ alive\n#\ until\ their\ slot\ is\ reused\ and\ the\ previous\ upload\ fence\ has\ signaled.\n\$gpuc\ code\ \{\n\ \ \ \ #define\ INFLIGHT_UPLOADS\ 8\n\ \ \ \ struct\ InflightUpload\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ cmdBuffer\;\n\ \ \ \ \ \ \ \ VkFence\ fence\;\n\ \ \ \ \ \ \ \ VkBuffer\ stagingBuffer\;\n\ \ \ \ \ \ \ \ VmaAllocation\ stagingBufferAllocation\;\n\ \ \ \ \ \ \ \ bool\ inUse\;\n\ \ \ \ \}\;\n\ \ \ \ static\ __thread\ struct\ InflightUpload\ _inflightUploads\[INFLIGHT_UPLOADS\]\;\n\ \ \ \ static\ __thread\ int\ _inflightUploadsNext\ =\ 0\;\n\n\ \ \ \ //\ Reclaim\ a\ slot:\ if\ it\ holds\ an\ outstanding\ upload,\ wait\ for\ its\n\ \ \ \ //\ fence,\ destroy\ its\ staging\ buffer,\ reset\ fence.\ Returns\ the\ slot\n\ \ \ \ //\ with\ fence\ +\ cmdBuffer\ allocated\ and\ ready\ to\ use.\n\ \ \ \ static\ struct\ InflightUpload*\ acquireInflightUpload()\ \{\n\ \ \ \ \ \ \ \ struct\ InflightUpload*\ slot\ =\ &_inflightUploads\[_inflightUploadsNext\]\;\n\ \ \ \ \ \ \ \ _inflightUploadsNext\ =\ (_inflightUploadsNext\ +\ 1)\ %\ INFLIGHT_UPLOADS\;\n\n\ \ \ \ \ \ \ \ if\ (slot->inUse)\ \{\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneN(ctx,\ \"vkWaitForFences\ (ring\ full)\",\ 1)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &slot->fence,\ VK_TRUE,\ UINT64_MAX)\;\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCZoneEnd(ctx)\;\n\ \ \ \ \ \ \ \ \ \ \ \ TracyCFree(slot->stagingBufferAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ \ \ \ \ vmaDestroyBuffer(vmaGetAllocator(),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer,\ slot->stagingBufferAllocation)\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBuffer\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->stagingBufferAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ \ \ \ \ slot->inUse\ =\ false\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->fence\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkCreateFence(device,\ &fenceInfo,\ NULL,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &slot->fence)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (slot->cmdBuffer\ ==\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkCommandBufferAllocateInfo\ allocInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandPool\ =\ getCommandPool()\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.level\ =\ VK_COMMAND_BUFFER_LEVEL_PRIMARY\;\n\ \ \ \ \ \ \ \ \ \ \ \ allocInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkAllocateCommandBuffers(device,\ &allocInfo,\ &slot->cmdBuffer)\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkResetCommandBuffer(slot->cmdBuffer,\ 0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ slot\;\n\ \ \ \ \}\n\}\n\n\$gpuc\ proc\ copyImageToGpuTexture\ \{Image\ im\}\ GpuTextureHandle\ \{\n\ \ \ \ struct\ InflightUpload*\ upload\ =\ acquireInflightUpload()\;\n\n\ \ \ \ size_t\ size\ =\ im.width\ *\ im.height\ *\ 4\;\n\ \ \ \ FOLK_ENSURE(size\ >\ 0)\;\n\n\ \ \ \ createBuffer(size,\ VK_BUFFER_USAGE_TRANSFER_SRC_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\ |\ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &upload->stagingBuffer,\ &upload->stagingBufferAllocation)\;\n\n\ \ \ \ //\ Copy\ im\ to\ stagingBuffer:\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ void*\ data\;\ vmaMapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation,\ &data)\;\n\ \ \ \ \ \ \ \ Image\ stagingIm\ =\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ im.width,\ .height\ =\ im.height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ im.width\ *\ 4,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \ \ \ \ copyImageToRgba(im,\ stagingIm)\;\n\ \ \ \ \ \ \ \ vmaUnmapMemory(vmaGetAllocator(),\ upload->stagingBufferAllocation)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Allocate\ a\ texture\ and\ texture\ block:\n\ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(im.width,\ im.height,\ VK_FORMAT_R8G8B8A8_SRGB)\;\n\n\ \ \ \ //\ Record\ +\ submit\ staging\ buffer\ ->\ image\ copy.\ We\ do\ NOT\ wait\ on\n\ \ \ \ //\ the\ fence\ here\;\ a\ later\ call\ to\ acquireInflightUpload\ will\n\ \ \ \ //\ reclaim\ this\ slot's\ staging\ buffer\ once\ the\ GPU\ is\ done.\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ upload->cmdBuffer\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ transfer\ destination\n\ \ \ \ \ \ \ \ VkImageMemoryBarrier\ barrier\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ barrier.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER\;\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.dstQueueFamilyIndex\ =\ VK_QUEUE_FAMILY_IGNORED\;\n\ \ \ \ \ \ \ \ barrier.image\ =\ block->textureImage\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\ VK_PIPELINE_STAGE_TRANSFER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ //\ Copy\ buffer\ to\ image\n\ \ \ \ \ \ \ \ VkBufferImageCopy\ region\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ region.bufferOffset\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferRowLength\ =\ 0\;\n\ \ \ \ \ \ \ \ region.bufferImageHeight\ =\ 0\;\n\n\ \ \ \ \ \ \ \ region.imageSubresource.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ region.imageSubresource.mipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ region.imageSubresource.layerCount\ =\ 1\;\n\n\ \ \ \ \ \ \ \ region.imageOffset\ =\ (VkOffset3D)\ \{0,\ 0,\ 0\}\;\n\ \ \ \ \ \ \ \ region.imageExtent\ =\ (VkExtent3D)\ \{im.width,\ im.height,\ 1\}\;\n\ \ \ \ \ \ \ \ vkCmdCopyBufferToImage(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ upload->stagingBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->textureImage,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ®ion)\;\n\n\ \ \ \ \ \ \ \ //\ Transition\ to\ shader\ read-only\n\ \ \ \ \ \ \ \ barrier.oldLayout\ =\ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.newLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ barrier.srcAccessMask\ =\ VK_ACCESS_TRANSFER_WRITE_BIT\;\n\ \ \ \ \ \ \ \ barrier.dstAccessMask\ =\ VK_ACCESS_SHADER_READ_BIT\;\n\n\ \ \ \ \ \ \ \ vkCmdPipelineBarrier(commandBuffer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_PIPELINE_STAGE_TRANSFER_BIT,\ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0,\ 0,\ NULL,\ 0,\ NULL,\ 1,\ &barrier)\;\n\n\ \ \ \ \ \ \ \ vkEndCommandBuffer(commandBuffer)\;\n\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ upload->fence)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ upload->inUse\ =\ true\;\n\ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ return\ block->handle\;\n\}\n#\ Replace\ a\ descriptor\ slot\ with\ a\ different\ texture.\ Must\ only\ be\n#\ called\ on\ the\ GPU\ thread\ between\ frames\ (used\ by\ canvases).\n\$gpuc\ proc\ replaceInTextureDescriptorSet\ \{GpuTextureHandle\ oldHandle\ GpuTextureHandle\ newHandle\}\ void\ \{\n\ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ imageInfo.imageView\ =\ gpuTextures\[newHandle\].textureImageView\;\n\ \ \ \ imageInfo.sampler\ =\ gpuTextures\[newHandle\].textureSampler\;\n\n\ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ descriptorWrite.dstArrayElement\ =\ oldHandle\;\n\ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\}\n\n\$gpuc\ proc\ freeGpuTexture\ \{GpuTextureHandle\ gim\}\ void\ \{\n\ \ \ \ enqueueDeferredTextureOp(DEFERRED_FREE,\ gim)\;\n\}\n\n#\ Actually\ destroy\ a\ texture's\ GPU\ resources.\ Must\ only\ be\ called\n#\ on\ the\ GPU\ thread\ between\ frames\ when\ the\ GPU\ is\ idle.\n\$gpuc\ code\ \{\n\ \ \ \ static\ void\ retireGpuTexture(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive\ ||\ block->retiring)\ return\;\n\n\ \ \ \ \ \ \ \ block->retiring\ =\ true\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ textureFrameEpoch\ +\ TEXTURE_RETIRE_GRACE_FRAMES\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyGpuTextureResources(GpuTextureHandle\ gim)\ \{\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ if\ (gim\ ==\ 0\ ||\ !block->alive)\ return\;\n\n\ \ \ \ \ \ \ \ //\ Point\ this\ descriptor\ slot\ at\ the\ placeholder\ texture\ (slot\ 0)\n\ \ \ \ \ \ \ \ //\ so\ later\ frames\ don't\ reference\ a\ destroyed\ image.\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkDescriptorImageInfo\ imageInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.imageView\ =\ gpuTextures\[0\].textureImageView\;\n\ \ \ \ \ \ \ \ \ \ \ \ imageInfo.sampler\ =\ gpuTextures\[0\].textureSampler\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkWriteDescriptorSet\ descriptorWrite\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.sType\ =\ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstBinding\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.dstArrayElement\ =\ gim\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorType\ =\ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.descriptorCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ descriptorWrite.pImageInfo\ =\ &imageInfo\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkUpdateDescriptorSets(device,\ 1,\ &descriptorWrite,\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \}\n\n#ifdef\ TRACY_ENABLE\n\ \ \ \ \ \ \ \ TracyCFree(block->textureImageAllocation)\;\n#endif\n\ \ \ \ \ \ \ \ vkDestroySampler(device,\ block->textureSampler,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyImageView(device,\ block->textureImageView,\ NULL)\;\n\ \ \ \ \ \ \ \ vmaDestroyImage(vmaGetAllocator(),\ block->textureImage,\ block->textureImageAllocation)\;\n\n\ \ \ \ \ \ \ \ free(block->description)\;\n\ \ \ \ \ \ \ \ block->description\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImage\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureImageAllocation\ =\ NULL\;\n\ \ \ \ \ \ \ \ block->textureImageView\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->textureSampler\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ block->retiring\ =\ false\;\n\ \ \ \ \ \ \ \ block->retireAfterFrame\ =\ 0\;\n\ \ \ \ \ \ \ \ block->alive\ =\ false\;\n\ \ \ \ \}\n\n\ \ \ \ static\ void\ destroyRetiredGpuTextures()\ \{\n\ \ \ \ \ \ \ \ for\ (GpuTextureHandle\ gim\ =\ 1\;\ gim\ <\ getMaxTextures()\;\ gim++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ &gpuTextures\[gim\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (block->alive\ &&\ block->retiring\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ block->retireAfterFrame\ <=\ textureFrameEpoch)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ destroyGpuTextureResources(gim)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\n#\ Called\ on\ the\ GPU\ thread\ before\ recording\ work\ that\ may\ sample\ textures.\n\$gpuc\ proc\ drainDeferredTextureOps\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&deferredQueueMutex)\;\n\ \ \ \ int\ count\ =\ deferredQueueCount\;\n\ \ \ \ struct\ DeferredTextureEntry\ localQueue\[DEFERRED_QUEUE_CAP\]\;\n\ \ \ \ memcpy(localQueue,\ deferredQueue,\ count\ *\ sizeof(struct\ DeferredTextureEntry))\;\n\ \ \ \ deferredQueueCount\ =\ 0\;\n\ \ \ \ pthread_mutex_unlock(&deferredQueueMutex)\;\n\n\ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ switch\ (localQueue\[i\].op)\ \{\n\ \ \ \ \ \ \ \ case\ DEFERRED_ADD:\n\ \ \ \ \ \ \ \ \ \ \ \ writeTextureDescriptor(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ case\ DEFERRED_FREE:\n\ \ \ \ \ \ \ \ \ \ \ \ retireGpuTexture(localQueue\[i\].handle)\;\n\ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ destroyRetiredGpuTextures()\;\n\}\n\n#\ Called\ once\ per\ GPU\ frame\ so\ retired\ textures\ age\ exactly\ once,\n#\ even\ though\ descriptor\ work\ may\ be\ drained\ multiple\ times.\n\$gpuc\ proc\ beginTextureFrame\ \{\}\ void\ \{\n\ \ \ \ textureFrameEpoch++\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\n\$gpuc\ proc\ initPlaceholderTexture\ \{\}\ void\ \{\n\ \ \ \ //\ Set\ up\ a\ placeholder\ texture\ in\ slot\ 0\ that\ can\ always\ be\ drawn\n\ \ \ \ //\ that\ we\ can\ swap\ in\ when\ textures\ get\ invalidated.\n\ \ \ \ Image\ debugIm\ =\ \{\n\ \ \ \ \ \ \ \ .width\ =\ 128,\ .height\ =\ 128,\n\ \ \ \ \ \ \ \ .components\ =\ 4,\n\ \ \ \ \ \ \ \ .bytesPerRow\ =\ 128\ *\ 4,\n\ \ \ \ \ \ \ \ .data\ =\ malloc(128\ *\ 128\ *\ 4)\n\ \ \ \ \}\;\n\ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ debugIm.height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ debugIm.width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ i\ =\ y\ *\ debugIm.bytesPerRow\ +\ x\ *\ debugIm.components\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+0\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+1\]\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+2\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \ \ \ \ debugIm.data\[i+3\]\ =\ 255\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ GpuTextureHandle\ han\ =\ copyImageToGpuTexture(debugIm)\;\n\ \ \ \ FOLK_ENSURE(han\ ==\ 0)\;\n\n\ \ \ \ //\ Fill\ all\ descriptor\ slots\ with\ the\ placeholder\ texture,\ then\n\ \ \ \ //\ drain\ the\ queued\ DEFERRED_ADD\ for\ slot\ 0\ (which\ is\ now\ redundant\n\ \ \ \ //\ but\ harmless).\n\ \ \ \ initializeDescriptorSet(han)\;\n\ \ \ \ drainDeferredTextureOps()\;\n\}\n\nset\ gpuTextureLib\ \[\$gpuc\ compile\]\n\n\$gpuTextureLib\ textureManagerInit\n\nClaim\ the\ GPU\ texture\ library\ is\ \$gpuTextureLib\n\nWhen\ /someone/\ wishes\ the\ GPU\ loads\ image\ /im/\ as\ texture\ \{\n\ \ \ \ set\ gtex\ \[\$gpuTextureLib\ copyImageToGpuTexture\ \$im\]\n\ \ \ \ Claim\ the\ GPU\ has\ loaded\ image\ \$im\ as\ texture\ \$gtex\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuTextureLib\ freeGpuTexture\ \$gtex\]\n\}\n\n\}\n
<unknown> claims builtin-programs/gpu/gpu.folk has program code {# gpu.folk --
#
# Sets up the GP (
[ m154:0 (s233:0) ]
)<unknown> claims builtin-programs/gpu/gpu.folk has program code {# gpu.folk --
#
# Sets up the GPU device.
if {[info exists this] && $::tcl_platform(os) eq "darwin"} {
# We hard-code gpu.folk into thread 0, so we should abort if not
# running that way.
return
}
fn defineVulkanHandleType {cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
}
Claim the GPU Vulkan handle type definer is [fn defineVulkanHandleType]
fn gpuInit {useGlfw} {
# First, we build the C GPU library, which can make direct calls into
# Vulkan -- this library then exposes functions that we can call from
# Tcl.
set gpuc [C]
$gpuc cflags -I./vendor
$gpuc include <pthread.h>
$gpuc code {
#define VOLK_IMPLEMENTATION
#include "volk/volk.h"
}
if {$useGlfw} {
$gpuc code {
// This must be included _after_ volk.h (Vulkan).
#include <GLFW/glfw3.h>
}
}
set macos [expr {$::tcl_platform(os) eq "darwin"}]
if {$macos} {
$gpuc cflags -I/opt/homebrew/include -L/opt/homebrew/lib
}
if {$useGlfw} {
$gpuc endcflags -lglfw
} else {
foreach renderFile [glob -nocomplain "/dev/dri/render*"] {
if {![file readable $renderFile]} {
puts stderr "Gpu: Warning: $renderFile is not readable by current user; Vulkan device may not appear.
Try doing `sudo chmod 666 $renderFile`."
}
}
}
$gpuc argtype VkResult { long $argname; __ENSURE_OK(Jim_GetLong(interp, $obj, &$argname)); }
$gpuc proc VkResultToString {VkResult res} char* {
switch (res) {
#define CASE(x) case VK_##x: return #x;
CASE(SUCCESS) CASE(NOT_READY)
CASE(TIMEOUT) CASE(EVENT_SET)
CASE(EVENT_RESET) CASE(INCOMPLETE)
CASE(ERROR_OUT_OF_HOST_MEMORY) CASE(ERROR_OUT_OF_DEVICE_MEMORY)
CASE(ERROR_INITIALIZATION_FAILED) CASE(ERROR_DEVICE_LOST)
CASE(ERROR_MEMORY_MAP_FAILED) CASE(ERROR_LAYER_NOT_PRESENT)
CASE(ERROR_EXTENSION_NOT_PRESENT) CASE(ERROR_FEATURE_NOT_PRESENT)
CASE(ERROR_INCOMPATIBLE_DRIVER) CASE(ERROR_TOO_MANY_OBJECTS)
CASE(ERROR_FORMAT_NOT_SUPPORTED) CASE(ERROR_FRAGMENTED_POOL)
CASE(ERROR_UNKNOWN) CASE(ERROR_OUT_OF_POOL_MEMORY)
CASE(ERROR_INVALID_EXTERNAL_HANDLE) CASE(ERROR_FRAGMENTATION)
CASE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS)
CASE(PIPELINE_COMPILE_REQUIRED) CASE(ERROR_SURFACE_LOST_KHR)
CASE(ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE(SUBOPTIMAL_KHR)
CASE(ERROR_OUT_OF_DATE_KHR) CASE(ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE(ERROR_VALIDATION_FAILED_EXT) CASE(ERROR_INVALID_SHADER_NV)
#ifdef VK_ENABLE_BETA_EXTENSIONS
CASE(ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR)
CASE(ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR)
#endif
CASE(ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT)
CASE(ERROR_NOT_PERMITTED_KHR)
CASE(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT)
CASE(THREAD_IDLE_KHR) CASE(THREAD_DONE_KHR)
CASE(OPERATION_DEFERRED_KHR) CASE(OPERATION_NOT_DEFERRED_KHR)
default: return "unknown";
}
#undef CASE
}
local proc vktry {call} { string map {\n " "} [csubst {{
VkResult res = $call;
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}}] }
$gpuc define {
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkPhysicalDeviceFeatures physicalDeviceFeatures;
VkPhysicalDeviceProperties physicalDeviceProperties;
VkDevice device;
uint32_t computeQueueFamilyIndex;
uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
pthread_mutex_t graphicsQueueMutex;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
pthread_mutex_t displaySurfaceMutex;
}
defineVulkanHandleType $gpuc VkPhysicalDevice
defineVulkanHandleType $gpuc VkDevice
$gpuc proc getPhysicalDevice {} VkPhysicalDevice { return physicalDevice; }
$gpuc proc getDevice {} VkDevice { return device; }
$gpuc proc init {bool useGlfw} void {
$[vktry volkInitialize()]
$[if {$useGlfw} { expr {"glfwInit();"} }]
// Set up VkInstance instance:
{
VkInstanceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
const char* validationLayers[] = {
"VK_LAYER_KHRONOS_validation"
};
createInfo.enabledLayerCount = sizeof(validationLayers)/sizeof(validationLayers[0]);
createInfo.ppEnabledLayerNames = validationLayers;
$[if {$macos} {subst -nocommands {
const char* enabledExtensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
"VK_EXT_metal_surface",
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}} elseif {$useGlfw} {subst -nocommands {
const char** enabledExtensions = glfwGetRequiredInstanceExtensions(&createInfo.enabledExtensionCount);
}} else {subst -nocommands {
const char* enabledExtensions[] = {
// 2 extensions for non-X11/Wayland display
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_DISPLAY_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
createInfo.enabledExtensionCount = sizeof(enabledExtensions)/sizeof(enabledExtensions[0]);
}}]
createInfo.ppEnabledExtensionNames = enabledExtensions;
$[if {$macos} { expr {{
createInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}} }]
VkResult res = vkCreateInstance(&createInfo, NULL, &instance);
if (res != VK_SUCCESS) {
FOLK_ERROR("Failed vkCreateInstance: %s (%d)\n",
VkResultToString(res), res);
if (res == VK_ERROR_LAYER_NOT_PRESENT) {
FOLK_ERROR("It looks like a required layer is missing.\n"
"Did you install `vulkan-validationlayers`?\n");
}
}
}
volkLoadInstance(instance);
// Set up VkPhysicalDevice physicalDevice
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (physicalDeviceCount == 0) {
FOLK_ERROR("Failed to find Vulkan physical device\n");
}
printf("gpu: Found %d Vulkan devices\n", physicalDeviceCount);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
physicalDevice = physicalDevices[0];
vkGetPhysicalDeviceFeatures(physicalDevice, &physicalDeviceFeatures);
vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
}
computeQueueFamilyIndex = UINT32_MAX; {
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, NULL);
VkQueueFamilyProperties queueFamilies[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies);
for (int i = 0; i < queueFamilyCount; i++) {
if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
computeQueueFamilyIndex = i;
}
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
graphicsQueueFamilyIndex = i;
break;
}
}
if (graphicsQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan graphics queue family\n"); exit(1);
}
if (computeQueueFamilyIndex == UINT32_MAX) {
fprintf(stderr, "Failed to find a Vulkan compute queue family\n"); exit(1);
}
}
// Set up VkDevice device
{
VkDeviceQueueCreateInfo queueCreateInfo = {0};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
queueCreateInfo.queueCount = 1;
float queuePriority = 1.0f;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures = {0};
$[if {$macos} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
"VK_KHR_portability_subset",
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}} elseif {$useGlfw} {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
}} else {subst -nocommands {
const char *deviceExtensions[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_MAINTENANCE3_EXTENSION_NAME
};
}}]
VkDeviceCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledLayerCount = 0;
createInfo.enabledExtensionCount = sizeof(deviceExtensions)/sizeof(deviceExtensions[0]);
createInfo.ppEnabledExtensionNames = deviceExtensions;
/* VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures = {0}; */
/* descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; */
/* descriptorIndexingFeatures.descriptorBindingPartiallyBound = VK_TRUE; */
/* // TODO: Do we need more descriptor indexing features? */
/* createInfo.pNext = &descriptorIndexingFeatures; */
$[vktry {vkCreateDevice(physicalDevice, &createInfo, NULL, &device)}]
}
// Set up VkQueue graphicsQueue and VkQueue presentQueue and VkQueue computeQueue
{
pthread_mutex_init(&graphicsQueueMutex, NULL);
pthread_mutex_init(&displaySurfaceMutex, NULL);
vkGetDeviceQueue(device, graphicsQueueFamilyIndex, 0, &graphicsQueue);
presentQueue = graphicsQueue;
computeQueue = graphicsQueue;
}
}
# Thread-local command pool and command buffer helpers. These are
# used by textures, canvases, and draw code across all displays.
$gpuc code {
__thread VkCommandPool _commandPool;
__thread VkCommandBuffer _commandBuffer;
}
defineVulkanHandleType $gpuc VkCommandPool
defineVulkanHandleType $gpuc VkCommandBuffer
$gpuc proc getCommandPool {} VkCommandPool {
if (_commandPool == 0) {
VkCommandPoolCreateInfo poolInfo = {0};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
poolInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
VkResult res = vkCreateCommandPool(device, &poolInfo, NULL, &_commandPool);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to create command pool: %d\\n", res); exit(1); }
}
return _commandPool;
}
$gpuc proc getCommandBuffer {} VkCommandBuffer {
if (_commandBuffer == 0) {
VkCommandBufferAllocateInfo allocInfo = {0};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = getCommandPool();
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(device, &allocInfo, &_commandBuffer);
if (res != VK_SUCCESS) { fprintf(stderr, "Failed to allocate command buffer: %d\\n", res); exit(1); }
}
return _commandBuffer;
}
$gpuc proc getDoesSupportShaderSampledImageArrayDynamicIndexing {} bool {
return physicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
}
$gpuc proc getMaxTextures {} int {
int maxTextures = physicalDeviceProperties.limits.maxPerStageDescriptorSamplers;
// COMBINED_IMAGE_SAMPLER counts against both sampler and sampled image limits.
int maxSampledImages = physicalDeviceProperties.limits.maxPerStageDescriptorSampledImages;
if (maxSampledImages < maxTextures) { maxTextures = maxSampledImages; }
// If it's actually a low cap (often 16), stick with that.
if (maxTextures < 128) { return maxTextures; }
// HACK: for now, I don't want to deal with all the other descriptor caps etc.
return 128;
}
set gpuLib [$gpuc compile]
$gpuLib init $useGlfw
Claim the GPU library is $gpuLib
Claim the GPU physical device is [$gpuLib getPhysicalDevice]
Claim the GPU device is [$gpuLib getDevice]
}
if {$::tcl_platform(os) eq "darwin"} {
gpuInit true
return
}
When $::thisNode has had displays enumerated {
# so we know that there isn't an extant Vulkan instance already.
When /nobody/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit false
}
When /someone/ wishes $::thisNode uses display "glfw" with /...any/ {
gpuInit true
}
}
}
<unknown> claims builtin-programs/gpu/draw.folk has program code #\ draw.folk\ --\n#\n#\ \ \ \ \ Prov (
[ m157:0 (s239:0) ]
)<unknown> claims builtin-programs/gpu/draw.folk has program code #\ draw.folk\ --\n#\n#\ \ \ \ \ Provides\ the\ ability\ to\ run\ pixel\ shaders\ with\ image\ and\n#\ \ \ \ \ numerical\ parameters\ (so\ you\ can\ draw\ images,\ shapes,\ etc.)\n#\ \ \ \ \ Single\ render\ thread\ handles\ all\ displays.\n\nif\ \{\[info\ exists\ this\]\ &&\ \$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ #\ We\ hard-code\ draw.folk\ into\ thread\ 0,\ so\ we\ should\ abort\ if\ not\n\ \ \ \ #\ running\ that\ way.\n\ \ \ \ return\n\}\n\nWhen\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ compiler\ library\ is\ /pipelineCompilerLib/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ On\ macOS\ we\ always\ use\ GLFW\;\ on\ Linux\ we\ use\ direct\ Vulkan\ display.\nset\ useGlfw\ \[expr\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\]\n\nset\ cc\ \[C\]\n\$cc\ cflags\ -I./vendor\n\$cc\ include\ <stdlib.h>\n\$cc\ include\ <unistd.h>\n\$cc\ include\ <pthread.h>\n\$cc\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\}\nif\ \{\$useGlfw\}\ \{\n\ \ \ \ \$cc\ code\ \{\n\ \ \ \ \ \ \ \ //\ This\ must\ be\ included\ _after_\ volk.h\ (Vulkan).\n\ \ \ \ \ \ \ \ #include\ <GLFW/glfw3.h>\n\ \ \ \ \}\n\ \ \ \ \$cc\ endcflags\ -lglfw\n\}\n\n\$cc\ extend\ \$gpuLib\n\$cc\ extend\ \$pipelineLib\n\nlocal\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ /*\ TODO:\ We\ also\ need\ to\ unwind\ all\ the\ GPU\ state.\ */\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ \$call:\ %s\ (%d)\\n\",\ VkResultToString(res),\ res)\;\n\ \ \ \ \}\n\}\}\]\ \}\n\n\$cc\ code\ \[subst\ \{\n\ \ \ \ typedef\ struct\ DisplayState\ \{\n\ \ \ \ \ \ \ \ VkSurfaceKHR\ surface\;\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchain\;\n\ \ \ \ \ \ \ \ uint32_t\ swapchainImageCount\;\n\ \ \ \ \ \ \ \ VkFormat\ swapchainImageFormat\;\n\ \ \ \ \ \ \ \ VkFramebuffer*\ swapchainFramebuffers\;\n\ \ \ \ \ \ \ \ VkExtent2D\ swapchainExtent\;\n\n\ \ \ \ \ \ \ \ uint32_t\ imageIndex\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ imageAvailableSemaphore\;\n\ \ \ \ \ \ \ \ VkSemaphore*\ renderFinishedSemaphores\;\n\ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \[expr\ \{\ \$useGlfw\ ?\ \"GLFWwindow*\ window\;\"\ :\ \"\"\ \}\]\n\ \ \ \ \}\ DisplayState\;\n\n\ \ \ \ VkDevice\ device\;\n\ \ \ \ VkPhysicalDevice\ physicalDevice\;\n\n\ \ \ \ static\ DisplayState*\ currentDisplay\;\n\ \ \ \ static\ VkPipeline\ boundPipeline\;\n\ \ \ \ static\ VkDescriptorSet\ boundDescriptorSet\;\n\}\]\n\n\$cc\ argtype\ DisplayState*\ \{\n\ \ \ \ DisplayState*\ \$argname\;\n\ \ \ \ sscanf(Jim_String(\$obj),\ \"(DisplayState*)\ %p\",\ &\$argname)\;\n\}\n\$cc\ rtype\ DisplayState*\ \{\n\ \ \ \ char\ buf\[100\]\;\n\ \ \ \ snprintf(buf,\ 100,\ \"(DisplayState*)\ %p\",\ \$rvalue)\;\n\ \ \ \ \$robj\ =\ Jim_NewStringObj(interp,\ buf,\ -1)\;\n\}\n\n\$cc\ proc\ initDisplay\ \{char*\ display\ uint32_t\ width\ uint32_t\ height\ uint32_t\ refreshRate\}\ DisplayState*\ \{\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ physicalDevice\ =\ *physicalDevice_ptr()\;\n\n\ \ \ \ DisplayState*\ ds\ =\ calloc(1,\ sizeof(DisplayState))\;\n\n\ \ \ \ //\ Get\ drawing\ surface.\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ glfwWindowHint(GLFW_CLIENT_API,\ GLFW_NO_API)\;\n\ \ \ \ \ \ \ \ ds->window\ =\ glfwCreateWindow(width,\ height,\ \"Folk\",\ NULL,\ NULL)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(ds->window\ !=\ NULL)\;\n\ \ \ \ \ \ \ \ if\ (glfwCreateWindowSurface(*instance_ptr(),\ ds->window,\ NULL,\ &ds->surface)\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ create\ GLFW\ window\ surface\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ :\ \[csubst\ \{\n\ \ \ \ \ \ \ \ //\ Search\ through\ displays\ to\ find\ the\ one\ matching\ display\ name\n\ \ \ \ \ \ \ \ int\ retries\ =\ 0\;\n\ \ \ \ \ \ \ \ VkDisplayKHR\ chosenDisplay\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ while\ (true)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ displayCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayPropertiesKHR\ displayProps\[displayCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice,\ &displayCount,\ displayProps)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ displayCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (displayProps\[i\].displayName\ &&\ strcmp(displayProps\[i\].displayName,\ display)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenDisplay\ =\ displayProps\[i\].display\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenDisplay\ !=\ VK_NULL_HANDLE)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ retries++\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (retries\ >\ 10)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"gpu/draw:\ Failed\ to\ find\ display\ '%s'\;\ retrying\ (retry\ %d).\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ retries)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ usleep(1000000)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Search\ through\ modes\ to\ find\ one\ matching\ width,\ height,\ and\ refreshRate\n\ \ \ \ \ \ \ \ uint32_t\ modeCount\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayModePropertiesKHR\ modeProps\[modeCount\]\;\n\ \ \ \ \ \ \ \ vkGetDisplayModePropertiesKHR(physicalDevice,\ chosenDisplay,\ &modeCount,\ modeProps)\;\n\n\ \ \ \ \ \ \ \ int\ chosenMode\ =\ -1\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ modeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (modeProps\[i\].parameters.visibleRegion.width\ ==\ width\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ modeProps\[i\].parameters.visibleRegion.height\ ==\ height\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ For\ some\ reason,\ refresh\ rate\ can\ vary\ by\ 1Hz-ish\ on\ the\ AnyBeam.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ abs((int)modeProps\[i\].parameters.refreshRate\ -\ (int)refreshRate)\ <\ 1000)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenMode\ =\ i\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (chosenMode\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ display\ mode\ on\ display\ '%s'\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"with\ width=%u\ height=%u\ refreshRate=%u\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ display,\ width,\ height,\ refreshRate)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ Find\ a\ display\ plane\ that\ supports\ chosenDisplay.\n\ \ \ \ \ \ \ \ uint32_t\ planeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkDisplayPlanePropertiesKHR\ planeProps\[planeCount\]\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice,\ &planeCount,\ planeProps)\;\n\n\ \ \ \ \ \ \ \ uint32_t\ chosenPlane\ =\ UINT32_MAX\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ p\ =\ 0\;\ p\ <\ planeCount\;\ p++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Skip\ planes\ already\ bound\ to\ a\ different\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (planeProps\[p\].currentDisplay\ !=\ VK_NULL_HANDLE\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ planeProps\[p\].currentDisplay\ !=\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Check\ that\ this\ plane\ supports\ our\ display.\n\ \ \ \ \ \ \ \ \ \ \ \ uint32_t\ supportedCount\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkDisplayKHR\ supported\[supportedCount\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice,\ p,\ &supportedCount,\ supported)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (uint32_t\ s\ =\ 0\;\ s\ <\ supportedCount\;\ s++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (supported\[s\]\ ==\ chosenDisplay)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ chosenPlane\ =\ p\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ break\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (chosenPlane\ !=\ UINT32_MAX)\ break\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"chosenPlane\ for\ '%s':\ %u\\n\",\ display,\ chosenPlane)\;\n\ \ \ \ \ \ \ \ if\ (chosenPlane\ ==\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ free(ds)\;\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ to\ find\ a\ display\ plane\ for\ display\ '%s'\\n\",\ display)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ VkDisplaySurfaceCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.displayMode\ =\ modeProps\[chosenMode\].displayMode\;\n\ \ \ \ \ \ \ \ createInfo.planeIndex\ =\ chosenPlane\;\n\ \ \ \ \ \ \ \ createInfo.transform\ =\ VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.alphaMode\ =\ VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ modeProps\[chosenMode\].parameters.visibleRegion\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateDisplayPlaneSurfaceKHR(*instance_ptr(),\ &createInfo,\ NULL,\ &ds->surface)\}\]\n\ \ \ \ \}\]\ \}\]\n\n\ \ \ \ uint32_t\ presentQueueFamilyIndex\;\ \{\n\ \ \ \ \ \ \ \ VkBool32\ presentSupport\ =\ 0\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice,\ *graphicsQueueFamilyIndex_ptr(),\ ds->surface,\ &presentSupport)\;\n\ \ \ \ \ \ \ \ if\ (!presentSupport)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Vulkan\ graphics\ queue\ family\ doesn't\ support\ presenting\ to\ surface\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ presentQueueFamilyIndex\ =\ *graphicsQueueFamilyIndex_ptr()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Figure\ out\ capabilities/format/mode\ of\ physical\ device\ for\ surface.\n\ \ \ \ VkSurfaceCapabilitiesKHR\ capabilities\;\n\ \ \ \ VkExtent2D\ extent\;\n\ \ \ \ uint32_t\ imageCount\;\n\ \ \ \ VkSurfaceFormatKHR\ surfaceFormat\;\n\ \ \ \ VkPresentModeKHR\ presentMode\;\ \{\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice,\ ds->surface,\ &capabilities)\;\n\n\ \ \ \ \ \ \ \ if\ (capabilities.currentExtent.width\ !=\ UINT32_MAX)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ extent\ =\ capabilities.currentExtent\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ glfwGetFramebufferSize(ds->window,\ (int*)\ &extent.width,\ (int*)\ &extent.height)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.width\ >\ extent.width)\ \{\ extent.width\ =\ capabilities.minImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.width\ <\ extent.width)\ \{\ extent.width\ =\ capabilities.maxImageExtent.width\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.minImageExtent.height\ >\ extent.height)\ \{\ extent.height\ =\ capabilities.minImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (capabilities.maxImageExtent.height\ <\ extent.height)\ \{\ extent.height\ =\ capabilities.maxImageExtent.height\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ :\ \{\}\ \}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ imageCount\ =\ capabilities.minImageCount\ +\ 1\;\n\ \ \ \ \ \ \ \ if\ (capabilities.maxImageCount\ >\ 0\ &&\ imageCount\ >\ capabilities.maxImageCount)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ imageCount\ =\ capabilities.maxImageCount\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ formatCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkSurfaceFormatKHR\ formats\[formatCount\]\;\n\ \ \ \ \ \ \ \ if\ (formatCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ surface\ formats.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice,\ ds->surface,\ &formatCount,\ formats)\;\n\ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[0\]\;\ //\ semi-arbitrary\ default\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ formatCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (formats\[i\].format\ ==\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ surfaceFormat\ =\ formats\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ uint32_t\ presentModeCount\;\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ NULL)\;\n\ \ \ \ \ \ \ \ VkPresentModeKHR\ presentModes\[presentModeCount\]\;\n\ \ \ \ \ \ \ \ if\ (presentModeCount\ ==\ 0)\ \{\ fprintf(stderr,\ \"No\ supported\ present\ modes.\\n\")\;\ exit(1)\;\ \}\n\ \ \ \ \ \ \ \ vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice,\ ds->surface,\ &presentModeCount,\ presentModes)\;\n\ \ \ \ \ \ \ \ presentMode\ =\ VK_PRESENT_MODE_FIFO_KHR\;\ //\ guaranteed\ to\ be\ available\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ presentModeCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (presentModes\[i\]\ ==\ VK_PRESENT_MODE_MAILBOX_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ presentMode\ =\ presentModes\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ VkSwapchainKHR\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSwapchainCreateInfoKHR\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR\;\n\ \ \ \ \ \ \ \ createInfo.surface\ =\ ds->surface\;\n\n\ \ \ \ \ \ \ \ createInfo.minImageCount\ =\ imageCount\;\n\ \ \ \ \ \ \ \ createInfo.imageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ createInfo.imageColorSpace\ =\ surfaceFormat.colorSpace\;\n\ \ \ \ \ \ \ \ createInfo.imageExtent\ =\ extent\;\n\ \ \ \ \ \ \ \ createInfo.imageArrayLayers\ =\ 1\;\n\ \ \ \ \ \ \ \ createInfo.imageUsage\ =\ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\;\n\n\ \ \ \ \ \ \ \ if\ (*graphicsQueueFamilyIndex_ptr()\ !=\ presentQueueFamilyIndex)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Graphics\ and\ present\ queue\ families\ differ\\n\")\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ createInfo.imageSharingMode\ =\ VK_SHARING_MODE_EXCLUSIVE\;\n\ \ \ \ \ \ \ \ createInfo.queueFamilyIndexCount\ =\ 0\;\n\ \ \ \ \ \ \ \ createInfo.pQueueFamilyIndices\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ createInfo.preTransform\ =\ capabilities.currentTransform\;\n\ \ \ \ \ \ \ \ createInfo.compositeAlpha\ =\ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\;\n\ \ \ \ \ \ \ \ createInfo.presentMode\ =\ presentMode\;\n\ \ \ \ \ \ \ \ createInfo.clipped\ =\ VK_TRUE\;\n\ \ \ \ \ \ \ \ createInfo.oldSwapchain\ =\ VK_NULL_HANDLE\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSwapchainKHR(device,\ &createInfo,\ NULL,\ &ds->swapchain)\}\]\n\ \ \ \ \}\n\n\ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ NULL)\;\n\ \ \ \ VkImage\ swapchainImages\[ds->swapchainImageCount\]\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ vkGetSwapchainImagesKHR(device,\ ds->swapchain,\ &ds->swapchainImageCount,\ swapchainImages)\;\n\ \ \ \ \ \ \ \ ds->swapchainImageFormat\ =\ surfaceFormat.format\;\n\ \ \ \ \ \ \ \ ds->swapchainExtent\ =\ extent\;\n\ \ \ \ \}\n\n\ \ \ \ VkImageView\ swapchainImageViews\[ds->swapchainImageCount\]\;\ \{\n\ \ \ \ \ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkImageViewCreateInfo\ createInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.sType\ =\ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.image\ =\ swapchainImages\[i\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.viewType\ =\ VK_IMAGE_VIEW_TYPE_2D\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.format\ =\ ds->swapchainImageFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.r\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.g\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.b\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.components.a\ =\ VK_COMPONENT_SWIZZLE_IDENTITY\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.aspectMask\ =\ VK_IMAGE_ASPECT_COLOR_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseMipLevel\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.levelCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.baseArrayLayer\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ createInfo.subresourceRange.layerCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateImageView(device,\ &createInfo,\ NULL,\ &swapchainImageViews\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ (ds->swapchainImageFormat\ !=\ VK_FORMAT_B8G8R8A8_UNORM)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Swapchain\ image\ format\ %d\ does\ not\ match\ pipeline\ render\ pass\ format\ (VK_FORMAT_B8G8R8A8_UNORM)\\n\",\ ds->swapchainImageFormat)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Set\ up\ framebuffers\n\ \ \ \ ds->swapchainFramebuffers\ =\ (VkFramebuffer\ *)\ malloc(sizeof(VkFramebuffer)\ *\ ds->swapchainImageCount)\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ swapchainImageViews\[i\]\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ ds->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ ds->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &ds->swapchainFramebuffers\[i\])\}\]\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSemaphoreCreateInfo\ semaphoreInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ semaphoreInfo.sType\ =\ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO\;\n\n\ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->imageAvailableSemaphore)\}\]\n\ \ \ \ \ \ \ \ ds->renderFinishedSemaphores\ =\ calloc(ds->swapchainImageCount,\ sizeof(VkSemaphore))\;\n\ \ \ \ \ \ \ \ for\ (uint32_t\ i\ =\ 0\;\ i\ <\ ds->swapchainImageCount\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateSemaphore(device,\ &semaphoreInfo,\ NULL,\ &ds->renderFinishedSemaphores\[i\])\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &ds->inFlightFence)\}\]\n\ \ \ \ \}\n\n\ \ \ \ return\ ds\;\n\}\n\$cc\ proc\ getDisplayWidth\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.width\;\ \}\n\$cc\ proc\ getDisplayHeight\ \{DisplayState*\ ds\}\ uint32_t\ \{\ return\ ds->swapchainExtent.height\;\ \}\n\n\$cc\ proc\ drawStart\ \{DisplayState*\ ds\}\ void\ \{\n\ \ \ \ currentDisplay\ =\ ds\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkResetFences(device,\ 1,\ &ds->inFlightFence)\;\n\n\ \ \ \ VkResult\ acquireResult\ =\ vkAcquireNextImageKHR(device,\ ds->swapchain,\ UINT64_MAX,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ds->imageAvailableSemaphore,\ VK_NULL_HANDLE,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ &ds->imageIndex)\;\n\ \ \ \ if\ (acquireResult\ !=\ VK_SUCCESS\ &&\ acquireResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkAcquireNextImageKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(acquireResult),\ acquireResult)\;\n\ \ \ \ \}\n\n\ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ *renderPass_ptr()\;\n\ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ ds->swapchainFramebuffers\[ds->imageIndex\]\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ ds->swapchainExtent\;\n\n\ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 1.0f\}\}\}\;\n\ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \}\n\n\ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\}\n\n#\ Draw\ to\ the\ screen\ using\ pipeline\ `pipeline`.\ Each\ arg\ in\ `args`\n#\ should\ be\ a\ push-constant\ parameter\ of\ the\ pipeline.\ Can\ only\ be\n#\ called\ between\ `drawStart`\ and\ `drawEnd`.\n\$cc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ currentDisplay->swapchainExtent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ currentDisplay->swapchainExtent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ currentDisplay->swapchainExtent\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \}\n\n\ \ \ \ VkDescriptorSet\ currentDescriptorSet\ =\ getTextureDescriptorSet()\;\n\ \ \ \ if\ (boundDescriptorSet\ !=\ currentDescriptorSet)\ \{\n\ \ \ \ \ \ \ \ bindTextureDescriptorSet(commandBuffer,\ pipeline.pipelineLayout)\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ currentDescriptorSet\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Gpu\ draw:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\}\n\n\$cc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ DisplayState*\ ds\ =\ currentDisplay\;\n\ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ VkSemaphore\ signalSemaphores\[\]\ =\ \{ds->renderFinishedSemaphores\[ds->imageIndex\]\}\;\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ VkSemaphore\ waitSemaphores\[\]\ =\ \{ds->imageAvailableSemaphore\}\;\n\ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ submitInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitSemaphores\ =\ waitSemaphores\;\n\ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ submitInfo.signalSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ submitInfo.pSignalSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\ ds->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \}\n\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ VkPresentInfoKHR\ presentInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ presentInfo.sType\ =\ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR\;\n\ \ \ \ \ \ \ \ presentInfo.waitSemaphoreCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pWaitSemaphores\ =\ signalSemaphores\;\n\n\ \ \ \ \ \ \ \ VkSwapchainKHR\ swapchains\[\]\ =\ \{ds->swapchain\}\;\n\ \ \ \ \ \ \ \ presentInfo.swapchainCount\ =\ 1\;\n\ \ \ \ \ \ \ \ presentInfo.pSwapchains\ =\ swapchains\;\n\ \ \ \ \ \ \ \ presentInfo.pImageIndices\ =\ &ds->imageIndex\;\n\ \ \ \ \ \ \ \ presentInfo.pResults\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ VkResult\ presentResult\ =\ vkQueuePresentKHR(*presentQueue_ptr(),\ &presentInfo)\;\n\ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ if\ (presentResult\ !=\ VK_SUCCESS\ &&\ presentResult\ !=\ VK_SUBOPTIMAL_KHR)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Failed\ vkQueuePresentKHR:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(presentResult),\ presentResult)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ //\ Wait\ for\ this\ display's\ submission\ to\ complete\ before\ we\n\ \ \ \ //\ reuse\ the\ shared\ command\ buffer\ for\ the\ next\ display.\n\ \ \ \ vkWaitForFences(device,\ 1,\ &ds->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ currentDisplay\ =\ NULL\;\n\}\n\n\$cc\ proc\ poll\ \{\}\ void\ \{\n\ \ \ \ \$\[expr\ \{\ \$useGlfw\ ?\ \{\ glfwPollEvents()\;\ \}\ :\ \{\}\ \}\]\n\}\n\nproc\ makeGpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\ return\ \[library\ create\ gpu\ \{gpuLib\ pipelineLib\ drawLib\}\ \{\n\ \ \ \ variable\ gpuLib\n\ \ \ \ variable\ pipelineLib\n\ \ \ \ variable\ drawLib\n\n\ \ \ \ if\ \{!\[exists\ -command\ \$drawLib\]\}\ \{\n\ \ \ \ \ \ \ \ #\ Load\ manually\ so\ we\ don't\ need\ to\ call\ a\ command.\n\ \ \ \ \ \ \ \ \$drawLib\n\ \ \ \ \}\n\n\ \ \ \ foreach\ drawLibCmd\ \[info\ commands\ \"\$drawLib\ *\"\]\ \{\n\ \ \ \ \ \ \ \ lassign\ \$drawLibCmd\ _\ drawLibCmd\n\ \ \ \ \ \ \ \ proc\ \$drawLibCmd\ \{args\}\ \{drawLib\ drawLibCmd\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ \"\$drawLib\ \$drawLibCmd\"\ \{*\}\$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\]\ \}\n\nset\ drawLib\ \[\$cc\ compile\]\nClaim\ the\ GPU\ draw\ library\ is\ \$drawLib\n\nset\ gpu\ \[makeGpu\ \$gpuLib\ \$pipelineLib\ \$drawLib\]\n\ntracy\ setThreadName\ \"gpu\"\n\n#\ Track\ initialized\ displays:\ dict\ mapping\ display\ name\ ->\ DisplayState*\nset\ displays\ \[dict\ create\]\n\nset\ kGpu\ \[tracy\ makeString\ \"gpu\"\]\nset\ kLatency\ \[tracy\ makeString\ \"latency\"\]\nset\ kQuadCount\ \[tracy\ makeString\ \"quadCount\"\]\nset\ kRegionCount\ \[tracy\ makeString\ \"regionCount\"\]\nset\ kDrawCount\ \[tracy\ makeString\ \"drawCount\"\]\n\nfn\ QueryAllFns!\ \{\}\ \{\n\ \ \ \ set\ fns\ \[dict\ create\]\n\ \ \ \ ForEach!\ /someone/\ claims\ the\ GPU\ compiles\ function\ /name/\ to\ /fn/\ \{\n\ \ \ \ \ \ \ \ dict\ set\ fns\ \$name\ \$fn\n\ \ \ \ \}\n\ \ \ \ return\ \$fns\n\}\nfn\ tryCompileFn\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ fn\ \[\$pipelineCompilerLib\ fn\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ #\ Technically\ a\ misnomer:\ the\ function\ is\ just\ stored,\ not\n\ \ \ \ \ \ \ \ #\ compiled\ until\ it's\ been\ inlined\ into\ a\ shader.\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ function\ \$name\ to\ \$fn\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ fn\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ function\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\nfn\ tryCompilePipeline\ \{wisher\ name\ source\}\ \{\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ fns\ \[QueryAllFns!\]\n\ \ \ \ \ \ \ \ set\ pipeline\ \[\$pipelineCompilerLib\ pipeline\ \$fns\ \{*\}\$source\]\n\n\ \ \ \ \ \ \ \ puts\ \"gpu:\ tryCompilePipeline:\ Compiled\ \$name\"\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$name\ to\ \$pipeline\n\n\ \ \ \ \}\ on\ 99\ notFoundName\ \{\n\ \ \ \ \ \ \ \ puts\ \"gpu\ pipeline\ \$name:\ Waiting\ for\ \$notFoundName\"\n\ \ \ \ \ \ \ \ When\ the\ GPU\ compiles\ function\ \$notFoundName\ to\ /anything/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Did\ compile\ \$notFoundName\"\n\ \ \ \ \ \ \ \ \ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ compiles\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\}\n\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ function\ /name/\ /source/\ \{\n\ \ \ \ tryCompileFn\ \$wisher\ \$name\ \$source\n\}\nWhen\ /wisher/\ wishes\ the\ GPU\ compiles\ pipeline\ /name/\ /source/\ \{\n\ \ \ \ tryCompilePipeline\ \$wisher\ \$name\ \$source\n\}\n\nset\ missingPipelines\ \[dict\ create\]\nwhile\ true\ \{\n\ \ \ \ #\ Advance\ texture\ retirement\ once\ per\ frame,\ then\ run\ canvas\ redraw\ work.\n\ \ \ \ \$gpuTextureLib\ beginTextureFrame\n\ \ \ \ ForEach!\ /someone/\ wishes\ the\ GPU\ runs\ frame\ prelude\ handler\ /hd/\ \{\n\ \ \ \ \ \ \ \ \{*\}\$hd\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ draw\ commands\ once\ (shared\ across\ all\ displays).\n\ \ \ \ set\ results\ \[Query!\ /someone/\ claims\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ set\ displayList\ \[dict\ create\]\n\ \ \ \ foreach\ result\ \[Query!\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ with\ /...options/\]\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ name\ \[dict\ get\ \$result\ name\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$name\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu:\ Missing\ pipeline\ \$name\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$name\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$name\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \[dict\ get\ \$result\ name\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ options\ \[dict\ get\ \$result\ options\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ displayList\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpu\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \[dict\ get\ \$result\ wisher\]\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Query\ active\ displays\;\ init\ new\ ones\ on\ first\ sight.\n\ \ \ \ foreach\ result\ \[Query!\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...displayOpts/\]\ \{\n\ \ \ \ \ \ \ \ set\ display\ \[dict\ get\ \$result\ display\]\n\ \ \ \ \ \ \ \ set\ displayOpts\ \[dict\ get\ \$result\ displayOpts\]\n\n\ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$displays\ \$display\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[Query!\ \$::thisNode\ has\ display\ \$display\ with\ /...any/\]\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"gpu/draw:\ Display\ '\$display'\ is\ wished\ but\ not\ enumerated\;\ skipping\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ missing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ds\ \[\$drawLib\ initDisplay\ \$display\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(width)\ \$displayOpts(height)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayOpts(refreshRate)\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ displays\ \$display\ \$ds\n\ \ \ \ \ \ \ \ \ \ \ \ Assert!\ display\ \$display\ has\ width\ \[\$drawLib\ getDisplayWidth\ \$ds\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[\$drawLib\ getDisplayHeight\ \$ds\]\n\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ get\ \$displays\ \$display\]\ eq\ \"missing\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ Allow\ for\ retry\ if\ display\ is\ plugged\ in\ later?\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Make\ textures\ published\ while\ building\ the\ display\ list\ drawable\n\ \ \ \ #\ before\ we\ record\ display\ command\ buffers.\n\ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ #\ Draw\ to\ each\ active\ display.\n\ \ \ \ dict\ for\ \{displayName\ ds\}\ \$displays\ \{\n\ \ \ \ \ \ \ \ if\ \{\$ds\ eq\ \"missing\"\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \$gpu\ drawStart\ \$ds\n\n\ \ \ \ \ \ \ \ set\ drawCount\ 0\n\ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$displayList\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layerDisplayList\ \[dict\ get\ \$displayList\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ displayCommand\ \$layerDisplayList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ drawCount\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$displayCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$gpu\ drawEnd\n\ \ \ \ \}\n\n\ \ \ \ tracy\ frameMarkNamed\ \$kGpu\n\n\ \ \ \ if\ \{\$useGlfw\}\ \{\ \$drawLib\ poll\ \}\n\ \ \ \ #\ TODO:\ sleep\ for\ 5ms\ or\ something?\n\}\n\n\}\n
<unknown> claims builtin-programs/gpu/canvases.folk has program code When\ the\ GPU\ library\ is\ /gp (
[ m158:0 (s244:0) ]
)<unknown> claims builtin-programs/gpu/canvases.folk has program code When\ the\ GPU\ library\ is\ /gpuLib/\ &\\\n\ \ \ \ \ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ &\\\n\ \ \ \ \ the\ GPU\ texture\ library\ is\ /gpuTextureLib/\ \{\n\ \ \ \ set\ gpuc\ \[C\]\n\ \ \ \ \$gpuc\ include\ <pthread.h>\n\ \ \ \ \$gpuc\ cflags\ -I./vendor\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ \ \ \ \ #include\ \"volk/volk.h\"\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$gpuLib\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ VkResultToString\n\ \ \ \ \$gpuc\ import\ \$gpuLib\ getCommandBuffer\n\n\ \ \ \ \$gpuc\ extend\ \$imageLib\n\ \ \ \ \$gpuc\ extend\ -noprocs\ \$pipelineLib\n\ \ \ \ \$gpuc\ extend\ \$gpuTextureLib\n\n\ \ \ \ local\ proc\ vktry\ \{call\}\ \{\ string\ map\ \{\\n\ \"\ \"\}\ \[csubst\ \{\{\n\ \ \ \ \ \ \ \ VkResult\ res\ =\ \$call\;\n\ \ \ \ \ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ \$call:\ %s\ (%d)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VkResultToString(res),\ res)\;\ exit(1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\]\ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ VkDevice\ device\;\n\ \ \ \ \ \ \ \ //\ Canvas\ format\ must\ match\ the\ pipeline\ render\ pass\ format\n\ \ \ \ \ \ \ \ //\ (VK_FORMAT_B8G8R8A8_UNORM)\ so\ that\ shared\ pipelines\ are\n\ \ \ \ \ \ \ \ //\ render-pass-compatible\ when\ drawing\ onto\ canvases.\n\ \ \ \ \ \ \ \ VkFormat\ canvasFormat\ =\ VK_FORMAT_B8G8R8A8_UNORM\;\n\n\ \ \ \ \ \ \ \ //\ This\ render\ pass\ is\ used\ to\ draw\ on\ all\ canvases.\n\ \ \ \ \ \ \ \ VkRenderPass\ renderPass\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ \$\[vktry\ volkInitialize()\]\n\ \ \ \ \ \ \ \ volkLoadInstanceOnly(*instance_ptr())\;\n\n\ \ \ \ \ \ \ \ device\ =\ *device_ptr()\;\n\ \ \ \ \ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ \ \ \ \ //\ Set\ up\ VkRenderPass\ renderPass:\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentDescription\ colorAttachment\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.format\ =\ canvasFormat\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.samples\ =\ VK_SAMPLE_COUNT_1_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.loadOp\ =\ VK_ATTACHMENT_LOAD_OP_CLEAR\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.storeOp\ =\ VK_ATTACHMENT_STORE_OP_STORE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilLoadOp\ =\ VK_ATTACHMENT_LOAD_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.stencilStoreOp\ =\ VK_ATTACHMENT_STORE_OP_DONT_CARE\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.initialLayout\ =\ VK_IMAGE_LAYOUT_UNDEFINED\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachment.finalLayout\ =\ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkAttachmentReference\ colorAttachmentRef\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.attachment\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ colorAttachmentRef.layout\ =\ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDescription\ subpass\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pipelineBindPoint\ =\ VK_PIPELINE_BIND_POINT_GRAPHICS\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.colorAttachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ subpass.pColorAttachments\ =\ &colorAttachmentRef\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassCreateInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pAttachments\ =\ &colorAttachment\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.subpassCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pSubpasses\ =\ &subpass\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubpassDependency\ dependency\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcSubpass\ =\ VK_SUBPASS_EXTERNAL\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstSubpass\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.srcAccessMask\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstStageMask\ =\ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ dependency.dstAccessMask\ =\ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.dependencyCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pDependencies\ =\ &dependency\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateRenderPass(device,\ &renderPassInfo,\ NULL,\ &renderPass)\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ typedef\ struct\ GpuCanvas\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkExtent2D\ extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ GpuTextureHandle\ gpuTexture\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkFramebuffer\ framebuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkFence\ inFlightFence\;\n\ \ \ \ \ \ \ \ \}\ GpuCanvas\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ gpuTexture\ \{GpuCanvas*\ wi\}\ GpuTextureHandle\ \{\n\ \ \ \ \ \ \ \ return\ wi->gpuTexture\;\n\ \ \ \ \}\n\n\ \ \ \ \$gpuc\ proc\ create\ \{int\ width\ int\ height\}\ GpuCanvas*\ \{\n\ \ \ \ \ \ \ \ GpuCanvas*\ wi\ =\ malloc(sizeof(GpuCanvas))\;\n\ \ \ \ \ \ \ \ wi->extent.width\ =\ width\;\ wi->extent.height\ =\ height\;\n\n\ \ \ \ \ \ \ \ GpuTextureBlock*\ block\ =\ createGpuTexture(width,\ height,\ canvasFormat)\;\n\ \ \ \ \ \ \ \ wi->gpuTexture\ =\ block->handle\;\n\ \ \ \ \ \ \ \ //\ make\ it\ immediately\ renderable\n\ \ \ \ \ \ \ \ transitionImageLayout(block->textureImage,\ canvasFormat,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_UNDEFINED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)\;\n\ \ \ \ \ \ \ \ addToTextureDescriptorSet(block->handle)\;\n\n\ \ \ \ \ \ \ \ VkImageView\ attachments\[\]\ =\ \{\ block->textureImageView\ \}\;\n\n\ \ \ \ \ \ \ \ VkFramebufferCreateInfo\ framebufferInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ framebufferInfo.sType\ =\ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO\;\n\ \ \ \ \ \ \ \ framebufferInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ framebufferInfo.attachmentCount\ =\ 1\;\n\ \ \ \ \ \ \ \ framebufferInfo.pAttachments\ =\ attachments\;\n\ \ \ \ \ \ \ \ framebufferInfo.width\ =\ width\;\n\ \ \ \ \ \ \ \ framebufferInfo.height\ =\ height\;\n\ \ \ \ \ \ \ \ framebufferInfo.layers\ =\ 1\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFramebuffer(device,\ &framebufferInfo,\ NULL,\ &wi->framebuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkFenceCreateInfo\ fenceInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.sType\ =\ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ fenceInfo.flags\ =\ VK_FENCE_CREATE_SIGNALED_BIT\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkCreateFence(device,\ &fenceInfo,\ NULL,\ &wi->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ return\ wi\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ destroy\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ freeGpuTexture(wi->gpuTexture)\;\n\ \ \ \ \ \ \ \ vkDestroyFramebuffer(device,\ wi->framebuffer,\ NULL)\;\n\ \ \ \ \ \ \ \ vkDestroyFence(device,\ wi->inFlightFence,\ NULL)\;\n\ \ \ \ \ \ \ \ free(wi)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ code\ \{\n\ \ \ \ \ \ \ \ __thread\ GpuCanvas*\ boundCanvas\;\n\ \ \ \ \ \ \ \ __thread\ VkPipeline\ boundPipeline\;\n\ \ \ \ \ \ \ \ __thread\ VkDescriptorSet\ boundDescriptorSet\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawStart\ \{GpuCanvas*\ wi\}\ void\ \{\n\ \ \ \ \ \ \ \ FOLK_ENSURE(boundCanvas\ ==\ NULL)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\n\ \ \ \ \ \ \ \ vkResetFences(device,\ 1,\ &wi->inFlightFence)\;\n\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\ \ \ \ \ \ \ \ vkResetCommandBuffer(commandBuffer,\ 0)\;\n\n\ \ \ \ \ \ \ \ //\ We\ can't\ have\ this\ texture\ in\ the\ descriptor\ set\ while\n\ \ \ \ \ \ \ \ //\ we're\ rendering\ to\ it.\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(wi->gpuTexture,\ 0)\;\n\n\ \ \ \ \ \ \ \ VkCommandBufferBeginInfo\ beginInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ beginInfo.sType\ =\ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ beginInfo.flags\ =\ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT\;\n\ \ \ \ \ \ \ \ beginInfo.pInheritanceInfo\ =\ NULL\;\n\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkBeginCommandBuffer(commandBuffer,\ &beginInfo)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkRenderPassBeginInfo\ renderPassInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.sType\ =\ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderPass\ =\ renderPass\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.framebuffer\ =\ wi->framebuffer\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.renderArea.extent\ =\ wi->extent\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkClearValue\ clearColor\ =\ \{\{\{0.0f,\ 0.0f,\ 0.0f,\ 0.0f\}\}\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.clearValueCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ renderPassInfo.pClearValues\ =\ &clearColor\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBeginRenderPass(commandBuffer,\ &renderPassInfo,\ VK_SUBPASS_CONTENTS_INLINE)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ boundCanvas\ =\ wi\;\n\ \ \ \ \ \ \ \ boundPipeline\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \ \ \ \ boundDescriptorSet\ =\ VK_NULL_HANDLE\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ draw\ \{Pipeline\ pipeline\ Jim_Obj*\ argsObj\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ if\ (boundPipeline\ !=\ pipeline.pipeline)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindPipeline(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\ pipeline.pipeline)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundPipeline\ =\ pipeline.pipeline\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkViewport\ viewport\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.x\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.y\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.width\ =\ (float)\ boundCanvas->extent.width\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.height\ =\ (float)\ boundCanvas->extent.height\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.minDepth\ =\ 0.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewport.maxDepth\ =\ 1.0f\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetViewport(commandBuffer,\ 0,\ 1,\ &viewport)\;\n\ \ \ \ \ \ \ \ \ \ \ \ VkRect2D\ scissor\ =\ \{0\}\;\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.offset\ =\ (VkOffset2D)\ \{0,\ 0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ scissor.extent\ =\ boundCanvas->extent\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdSetScissor(commandBuffer,\ 0,\ 1,\ &scissor)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ (boundDescriptorSet\ !=\ *textureDescriptorSet_ptr())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdBindDescriptorSets(commandBuffer,\ VK_PIPELINE_BIND_POINT_GRAPHICS,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pipelineLayout,\ 0,\ 1,\ textureDescriptorSet_ptr(),\ 0,\ NULL)\;\n\ \ \ \ \ \ \ \ \ \ \ \ boundDescriptorSet\ =\ *textureDescriptorSet_ptr()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ pushConstantsData\[128\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ pushConstantsDataSize\ =\ pipeline.encodePushConstants->encode(interp,\ argsObj,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ABORT()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (pushConstantsDataSize\ !=\ pipeline.pushConstantsSize)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"drawImpl:\ Expected\ push\ constants\ size\ %zu\;\ push\ constants\ data\ size\ was\ %d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsDataSize)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ vkCmdPushConstants(commandBuffer,\ pipeline.pipelineLayout,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ VK_SHADER_STAGE_VERTEX_BIT\ |\ VK_SHADER_STAGE_FRAGMENT_BIT,\ 0,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pipeline.pushConstantsSize,\ pushConstantsData)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ //\ 1\ quad\ ->\ 2\ triangles\ ->\ 6\ vertices\n\ \ \ \ \ \ \ \ vkCmdDraw(commandBuffer,\ 6,\ 1,\ 0,\ 0)\;\n\ \ \ \ \}\n\ \ \ \ \$gpuc\ proc\ drawEnd\ \{\}\ void\ \{\n\ \ \ \ \ \ \ \ VkCommandBuffer\ commandBuffer\ =\ getCommandBuffer()\;\n\n\ \ \ \ \ \ \ \ vkCmdEndRenderPass(commandBuffer)\;\n\ \ \ \ \ \ \ \ \$\[vktry\ \{vkEndCommandBuffer(commandBuffer)\}\]\n\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ VkSubmitInfo\ submitInfo\ =\ \{0\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.sType\ =\ VK_STRUCTURE_TYPE_SUBMIT_INFO\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ VkPipelineStageFlags\ waitStages\[\]\ =\ \{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT\}\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pWaitDstStageMask\ =\ waitStages\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.commandBufferCount\ =\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ submitInfo.pCommandBuffers\ =\ &commandBuffer\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_lock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[vktry\ \{vkQueueSubmit(*graphicsQueue_ptr(),\ 1,\ &submitInfo,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->inFlightFence)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ pthread_mutex_unlock(graphicsQueueMutex_ptr())\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ vkWaitForFences(device,\ 1,\ &boundCanvas->inFlightFence,\ VK_TRUE,\ UINT64_MAX)\;\n\n\ \ \ \ \ \ \ \ replaceInTextureDescriptorSet(boundCanvas->gpuTexture,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boundCanvas->gpuTexture)\;\n\ \ \ \ \ \ \ \ boundCanvas\ =\ NULL\;\n\ \ \ \ \}\n\n\ \ \ \ set\ gpuCanvasLib\ \[\$gpuc\ compile\]\n\ \ \ \ Claim\ the\ GPU\ canvas\ library\ is\ \$gpuCanvasLib\n\n\ \ \ \ \$gpuCanvasLib\ init\n\n\ \ \ \ #\ `id`\ is\ arbitrarily\ chosen\ by\ the\ caller:\n\ \ \ \ When\ /someone/\ wishes\ the\ GPU\ creates\ canvas\ /id/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ puts\ \"Create\ canvas:\ \$id\"\n\n\ \ \ \ \ \ \ \ dict\ set\ options\ width\ \[dict\ getdef\ \$options\ width\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ height\ \[dict\ getdef\ \$options\ height\ 1024\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ settle\ \[dict\ getdef\ \$options\ settle\ 3ms\]\n\n\ \ \ \ \ \ \ \ set\ wi\ \[\$gpuCanvasLib\ create\ \$options(width)\ \$options(height)\]\n\n\ \ \ \ \ \ \ \ Claim\ the\ GPU\ has\ created\ canvas\ \$id\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$options\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ texture\ \[\$gpuCanvasLib\ gpuTexture\ \$wi\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ writableInfo\ \$wi\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$gpuCanvasLib\ destroy\ \$wi\]\n\n\ \ \ \ \ \ \ \ Wish\ to\ collect\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ settle\ \$options(settle)\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ runs\ frame\ prelude\ handler\ \[list\ apply\ \{\{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\}\ \$gpuCanvasLib\ \$gpuTextureLib\]\n\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ \{\n\ \ \ \ \ \ \ \ Wish\ \$p\ has\ a\ canvas\ with\ width\ 1024\ height\ 1024\ settle\ 3ms\n\ \ \ \ \}\n\ \ \ \ When\ /someone/\ wishes\ /p/\ has\ a\ canvas\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ this\ matches\ even\ if\ the\ options\ aren't\n\ \ \ \ \ \ \ \ \ \ \ \ #\ there.\ just\ return\ early\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ pCanvas\ \[list\ \$p\ canvas\]\n\ \ \ \ \ \ \ \ #\ -keep\ is\ to\ deduplicate\ canvases\ and\ reduce\ canvas\ churn.\n\ \ \ \ \ \ \ \ Wish\ -keep\ 100ms\ the\ GPU\ creates\ canvas\ \$pCanvas\ with\ \{*\}\$options\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$pCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ \$pCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ width\ \[dict\ get\ \$geom\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ height\ \[dict\ get\ \$geom\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ proj\ \[list\ \[list\ \$(2.0/\$width)\ 0\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$(2.0/\$height)\ -1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$p\ has\ canvas\ projection\ \$proj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ Wish\ the\ GPU\ compiles\ pipeline\ \"composite-canvas\"\ \{\n\ \ \ \ \ \ \ \ \{vec2\ viewport\ mat3\ surfaceToClip\n\ \ \ \ \ \ \ \ \ \ \ \ sampler2D\ image\ vec2\ a\ vec2\ b\ vec2\ c\ vec2\ d\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](a,\ b,\ c,\ a,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ v\ =\ surfaceToClip\ *\ vec3(vertices\[gl_VertexIndex\],\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(v.xy/v.z,\ 0.0,\ 1.0)\;\n\n\ \ \ \ \ \ \ \ \}\ \{fn\ invBilinear\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ clipXy\ =\ (gl_FragCoord.xy\ /\ viewport)\ *\ 2.0\ -\ 1.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec3\ surfaceXy\ =\ inverse(surfaceToClip)\ *\ vec3(clipXy,\ 1.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ surfaceXy\ /=\ surfaceXy.z\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ invBilinear(surfaceXy.xy,\ a,\ b,\ c,\ d)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if(\ max(\ abs(uv.x-0.5),\ abs(uv.y-0.5))<0.5\ )\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec4\ texColor\ =\ texture(image,\ uv)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Prevent\ divide-by-zero\ errors\ on\ empty\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (texColor.a\ <\ 0.001)\ return\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Un-premultiply!\ The\ compiler's\ auto-premultiply\ will\ cancel\ this\ out,\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ leaving\ the\ canvas\ pixels\ mathematically\ untouched.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(texColor.rgb\ /\ texColor.a,\ texColor.a)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ vec4(0.0)\;\n\ \ \ \ \}\}\n\n\ \ \ \ When\ display\ /disp/\ has\ width\ /dispWidth/\ height\ /dispHeight/\ \{\n\ \ \ \ \ \ \ \ #\ Create\ a\ canvas\ wrapper\ around\ the\ bare\ display\ so\ that\ you\n\ \ \ \ \ \ \ \ #\ can\ draw\ onto\ it\ using\ the\ canvas-oriented\ interface.\n\ \ \ \ \ \ \ \ set\ dispCanvas\ \[list\ \$disp\ canvas\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ creates\ canvas\ \$dispCanvas\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ width\ \$dispWidth\ height\ \$dispHeight\ settle\ 0ms\ layer\ 100\n\n\ \ \ \ \ \ \ \ When\ the\ GPU\ has\ created\ canvas\ \$dispCanvas\ with\ /...canvOpts/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ \$dispCanvas\ with\ \{*\}\$canvOpts\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ HACK:\ for\ now,\ we\ just\ impose\ a\ surfaceToClip\ that\ means\n\ \ \ \ \ \ \ \ \ \ \ \ #\ you\ draw\ onto\ the\ display\ canvas\ in\ screen-space\ pixels\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (not\ meters,\ yet\ --\ what\ would\ that\ mean\ without\n\ \ \ \ \ \ \ \ \ \ \ \ #\ awareness\ of\ a\ specific\ table/plane?).\n\ \ \ \ \ \ \ \ \ \ \ \ set\ surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[expr\ \{2.0\ /\ \$dispWidth\}\]\ 0\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \[expr\ \{2.0\ /\ \$dispHeight\}\]\ -1.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\ 1\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$disp\ has\ canvas\ projection\ \$surfaceToClip\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Actually\ draw\ the\ canvas\ onto\ the\ bare\ display.\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vertex\ order\ needs\ to\ be\ clockwise\ to\ align\ with\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Vulkan.\ Top-left\ to\ bottom-left.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ a\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ b\ \[list\ \$dispWidth\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ c\ \[list\ \$dispWidth\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ d\ \[list\ 0\ \$dispHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"composite-canvas\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$dispWidth\ \$dispHeight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$canvOpts\ texture\]\ \$a\ \$b\ \$c\ \$d\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ \[dict\ getdef\ \$canvOpts\ layer\ 99\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/gpu/toy-shader.folk has program code #\ sha1\ for\ stable,\ content (
[ m159:0 (s243:0) ]
)<unknown> claims builtin-programs/gpu/toy-shader.folk has program code #\ sha1\ for\ stable,\ content-addressed\ pipeline\ names.\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <openssl/sha.h>\n\$cc\ proc\ sha1\ \{char*\ d\}\ Jim_Obj*\ \{\n\ \ \ \ unsigned\ char\ md\[20\]\;\n\ \ \ \ SHA1((unsigned\ char\ *)d,\ strlen(d),\ md)\;\n\ \ \ \ return\ Jim_NewStringObj(interp,\ (char\ *)md,\ 20)\;\n\}\n\$cc\ endcflags\ -lssl\ -lcrypto\nset\ sha1Lib\ \[\$cc\ compile\]\n\nWhen\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ &\\\n\ \ \ \ \ the\ GPU\ pipeline\ library\ is\ /pipelineLib/\ \{\n\n#\ Custom\ push-constants\ encoder\ for\ ShaderToy\ uniforms.\n#\ Layout\ (std430):\n#\ \ \ offset\ \ 0\ \ vec3\ \ iResolution\ \ \ \ (12\ bytes\ —\ no\ trailing\ pad,\n#\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ since\ the\ next\ member\ is\ a\ scalar)\n#\ \ \ offset\ 12\ float\ iTime\ \ \ \ \ \ \ \ \ \ (4\ bytes)\n#\n#\ Wish\ arguments:\ \[list\ \$resolution\ \$iTime\]\nset\ cc\ \[C\]\n\$cc\ include\ <string.h>\n\$cc\ include\ <stdint.h>\n\$cc\ code\ \{\n\ \ \ \ //\ HACK:\ copied\ from\ pipelines.folk\n\ \ \ \ typedef\ struct\ PushConstantsEncoder\ \{\n\ \ \ \ \ \ \ \ int\ (*encode)(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\;\n\ \ \ \ \}\ PushConstantsEncoder\;\n\n\ \ \ \ typedef\ struct\ Args\ \{\n\ \ \ \ \ \ \ \ float\ iResolution\[3\]\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ Args\;\n\n\ \ \ \ static\ int\ encodeToy(Jim_Interp*\ interp,\ Jim_Obj*\ obj,\ uint8_t\ out\[128\])\ \{\n\ \ \ \ \ \ \ \ Args\ args\ =\ \{0\}\;\n\n\ \ \ \ \ \ \ \ //\ iResolution:\ caller\ passes\ \{width\ height\}\;\ we\ synthesize\ z=1.\n\ \ \ \ \ \ \ \ Jim_Obj*\ resObj\ =\ Jim_ListGetIndex(interp,\ obj,\ 0)\;\n\ \ \ \ \ \ \ \ if\ (Jim_ListLength(interp,\ resObj)\ !=\ 2)\ return\ -1\;\n\ \ \ \ \ \ \ \ double\ w,\ h\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 0),\ &w)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ resObj,\ 1),\ &h)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iResolution\[0\]\ =\ (float)w\;\n\ \ \ \ \ \ \ \ args.iResolution\[1\]\ =\ (float)h\;\n\ \ \ \ \ \ \ \ args.iResolution\[2\]\ =\ 1.0f\;\n\n\ \ \ \ \ \ \ \ //\ iTime:\ seconds\ since\ shader\ load.\n\ \ \ \ \ \ \ \ double\ t\;\n\ \ \ \ \ \ \ \ if\ (Jim_GetDouble(interp,\ Jim_ListGetIndex(interp,\ obj,\ 1),\ &t)\ !=\ JIM_OK)\ return\ -1\;\n\ \ \ \ \ \ \ \ args.iTime\ =\ (float)t\;\n\n\ \ \ \ \ \ \ \ memcpy(out,\ &args,\ sizeof(args))\;\n\ \ \ \ \ \ \ \ return\ sizeof(args)\;\n\ \ \ \ \}\n\}\n\$cc\ proc\ makeToyEncoder\ \{\}\ PushConstantsEncoder*\ \{\n\ \ \ \ PushConstantsEncoder*\ e\ =\ malloc(sizeof(PushConstantsEncoder))\;\n\ \ \ \ e->encode\ =\ encodeToy\;\n\ \ \ \ return\ e\;\n\}\n\$cc\ proc\ getToyArgsSize\ \{\}\ int\ \{\ return\ sizeof(Args)\;\ \}\nset\ toyEncoderLib\ \[\$cc\ compile\]\n\nset\ toyEncoder\ \[\$toyEncoderLib\ makeToyEncoder\]\nset\ toyArgsSize\ \[\$toyEncoderLib\ getToyArgsSize\]\n\n#\ Run\ glslc\ as\ a\ subprocess\ to\ turn\ GLSL\ into\ SPIR-V\ words.\nfn\ toyGlslc\ \{stage\ glsl\}\ \{\n\ \ \ \ set\ glslfile\ \[file\ tempfile\ /tmp/toyshaderXXXXXX\].glsl\n\ \ \ \ set\ glslfd\ \[open\ \$glslfile\ w\]\;\ puts\ \$glslfd\ \$glsl\;\ close\ \$glslfd\n\ \ \ \ split\ \[string\ map\ \{\\n\ \"\"\}\ \[exec\ glslc\ -fshader-stage=\$stage\ -mfmt=num\ -o\ -\ \$glslfile\]\]\ \",\"\n\}\n\nset\ toyPushConstantsBlock\ \{\n\ \ \ \ layout(push_constant)\ uniform\ Args\ \{\n\ \ \ \ \ \ \ \ vec3\ iResolution\;\n\ \ \ \ \ \ \ \ float\ iTime\;\n\ \ \ \ \}\ args\;\n\}\n\nWhen\ /wisher/\ wishes\ /p/\ draws\ toy\ shader\ /shaderCode/\ \{\n\ \ \ \ binary\ scan\ \[\$sha1Lib\ sha1\ \$shaderCode\]\ H*\ sha1\n\n\ \ \ \ set\ vertGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec2\ vUv\;\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ vertices\[6\]\ =\ vec2\[6\](\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 0.0),\ vec2(1.0,\ 1.0),\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vec2(0.0,\ 0.0),\ vec2(1.0,\ 1.0),\ vec2(0.0,\ 1.0)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ uv\ =\ vertices\[gl_VertexIndex\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ vUv\ =\ uv\;\n\ \ \ \ \ \ \ \ \ \ \ \ gl_Position\ =\ vec4(uv\ *\ 2.0\ -\ 1.0,\ 0.0,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Attribute\ glslc\ errors\ back\ to\ the\ wisher's\ .folk\ source\ by\n\ \ \ \ #\ pulling\ source\ info\ off\ the\ matched\ `Wish\ X\ draws\ toy\ shader`\n\ \ \ \ #\ statement.\n\ \ \ \ lassign\ \[__statementOfCurrentMatchSourceInfo\]\ wishFile\ wishLine\n\ \ \ \ if\ \{\$wishLine\ eq\ \{\}\}\ \{\ set\ wishLine\ 1\ \}\n\ \ \ \ set\ fragGlsl\ \[csubst\ \{\n\ \ \ \ \ \ \ \ #version\ 450\n\n\ \ \ \ \ \ \ \ \$toyPushConstantsBlock\n\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ in\ vec2\ vUv\;\n\ \ \ \ \ \ \ \ layout(location\ =\ 0)\ out\ vec4\ outColor\;\n\n\ \ \ \ \ \ \ \ //\ Expose\ ShaderToy's\ built-in\ uniforms\ by\ the\ names\ user\ code\ expects.\n\ \ \ \ \ \ \ \ #define\ iResolution\ args.iResolution\n\ \ \ \ \ \ \ \ #define\ iTime\ args.iTime\n\n\ \ \ \ \ \ \ \ #line\ \$wishLine\ \"\$wishFile\"\n\ \ \ \ \ \ \ \ \$shaderCode\n\n\ \ \ \ \ \ \ \ void\ main()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ vec2\ fragCoord\ =\ vUv\ *\ iResolution.xy\;\n\ \ \ \ \ \ \ \ \ \ \ \ vec4\ fragColor\ =\ vec4(0.0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ mainImage(fragColor,\ fragCoord)\;\n\ \ \ \ \ \ \ \ \ \ \ \ //\ ShaderToy\ convention\ ignores\ alpha\;\ force\ opaque.\n\ \ \ \ \ \ \ \ \ \ \ \ outColor\ =\ vec4(fragColor.rgb,\ 1.0)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ vertShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ vert\ \$vertGlsl\]\]\n\ \ \ \ \ \ \ \ set\ fragShaderModule\ \[\$pipelineLib\ createShaderModule\ \[toyGlslc\ frag\ \$fragGlsl\]\]\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ puts\ stderr\ \"Error\ compiling\ toy\ shader:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ Claim\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \}\n\n\ \ \ \ set\ pipeline\ \[\$pipelineLib\ createPipeline\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$vertShaderModule\ \$fragShaderModule\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$toyEncoder\ \$toyArgsSize\]\n\n\ \ \ \ Claim\ the\ GPU\ compiles\ pipeline\ \$sha1\ to\ \$pipeline\n\n\ \ \ \ set\ startTime\ \[/\ \[clock\ microseconds\]\ 1000000.0\]\n\ \ \ \ When\ \$p\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \$sha1\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \$wiResolution\ \[-\ \$t\ \$startTime\]\]\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/gpu/vma.folk has program code When\ the\ GPU\ Vulkan\ handle\ type\ (
[ m161:0 (s246:0) ]
)<unknown> claims builtin-programs/gpu/vma.folk has program code When\ the\ GPU\ Vulkan\ handle\ type\ definer\ is\ /defineVulkanHandleType/\ \{\n\nfn\ defineVulkanHandleType\n\n#\ VMA\ (Vulkan\ Memory\ Allocator)\ module:\nset\ vmac\ \[C++\]\n\$vmac\ cflags\ -I./vendor\ \\\n\ \ \ \ -Wno-nullability-completeness\ -Wno-unused-private-field\ \\\n\ \ \ \ -Wno-unused-variable\n\$vmac\ code\ \{\n\ \ \ \ #define\ VOLK_IMPLEMENTATION\n\ \ \ \ #include\ \"volk/volk.h\"\n\n\ \ \ \ #define\ VMA_IMPLEMENTATION\n\ \ \ \ #define\ VMA_STATIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #define\ VMA_DYNAMIC_VULKAN_FUNCTIONS\ 0\n\ \ \ \ #include\ \"vk_mem_alloc.h\"\n\n\ \ \ \ VmaAllocator\ allocator\ =\ VK_NULL_HANDLE\;\n\}\ndefineVulkanHandleType\ \$vmac\ VkInstance\ndefineVulkanHandleType\ \$vmac\ VkPhysicalDevice\ndefineVulkanHandleType\ \$vmac\ VkDevice\n\$vmac\ code\ \{\ extern\ \"C\"\ \{\n\nvoid\ vmaInit(VkInstance\ instance,\ VkPhysicalDevice\ physicalDevice,\ VkDevice\ device,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetInstanceProcAddr\ vkGetInstanceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetDeviceProcAddr\ vkGetDeviceProcAddr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceProperties\ vkGetPhysicalDeviceProperties,\n\ \ \ \ \ \ \ \ \ \ \ \ \ PFN_vkGetPhysicalDeviceMemoryProperties\ vkGetPhysicalDeviceMemoryProperties)\ \{\n\ \ \ \ if\ (allocator\ !=\ VK_NULL_HANDLE)\ \{\ return\;\ \}\n\n\ \ \ \ volkInitialize()\;\n\ \ \ \ volkLoadInstanceOnly(instance)\;\n\ \ \ \ volkLoadDevice(device)\;\n\n\ \ \ \ VmaAllocatorCreateInfo\ allocatorInfo\ =\ \{0\}\;\n\ \ \ \ allocatorInfo.physicalDevice\ =\ physicalDevice\;\n\ \ \ \ allocatorInfo.device\ =\ device\;\n\ \ \ \ allocatorInfo.instance\ =\ instance\;\n\n\ \ \ \ VmaVulkanFunctions\ vulkanFunctions\;\n\ \ \ \ VkResult\ res\ =\ vmaImportVulkanFunctionsFromVolk(&allocatorInfo,\ &vulkanFunctions)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ import\ Vulkan\ functions\ from\ volk:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ HACK:\ We\ need\ the\ caller\ to\ get\ these\ from\ their\ namespace\ and\n\ \ \ \ //\ pass\ them\ in\;\ they're\ global\ and\ don't\ get\ bound\ properly\ by\n\ \ \ \ //\ Volk\ if\ we\ get\ them\ from\ here.\n\ \ \ \ vulkanFunctions.vkGetInstanceProcAddr\ =\ vkGetInstanceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetDeviceProcAddr\ =\ vkGetDeviceProcAddr\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceProperties\ =\ vkGetPhysicalDeviceProperties\;\n\ \ \ \ vulkanFunctions.vkGetPhysicalDeviceMemoryProperties\ =\ vkGetPhysicalDeviceMemoryProperties\;\n\n\ \ \ \ allocatorInfo.pVulkanFunctions\ =\ &vulkanFunctions\;\n\n\ \ \ \ res\ =\ vmaCreateAllocator(&allocatorInfo,\ &allocator)\;\n\ \ \ \ if\ (res\ !=\ VK_SUCCESS)\ \{\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"Failed\ to\ create\ VMA\ allocator:\ %d\\\\n\",\ res)\;\n\ \ \ \ \ \ \ \ exit(1)\;\n\ \ \ \ \}\n\}\n\nVmaAllocator\ vmaGetAllocator()\ \{\n\ \ \ \ return\ allocator\;\n\}\n\n\}\ \}\n\nset\ vmaDll\ \[\$vmac\ compile\ -noload\]\nClaim\ the\ GPU\ VMA\ DLL\ is\ \$vmaDll\n\n\}\n
<unknown> claims builtin-programs/gpu/gpu-fns.folk has program code {Wish the GPU compiles function " (
[ m163:0 (s250:0) ]
)<unknown> claims builtin-programs/gpu/gpu-fns.folk has program code {Wish the GPU compiles function "rotate" {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
Wish the GPU compiles function "wedge2d" {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
# See https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/
Wish the GPU compiles function "invBilinear" {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
}
<unknown> claims builtin-programs/shapes/region.folk has program code #\ Creates\ an\ id\ \"\$\{p\}:\ (
[ m167:0 (s254:0) ]
)<unknown> claims builtin-programs/shapes/region.folk has program code #\ Creates\ an\ id\ \"\$\{p\}:\$\{index\}\"\ and\ assigns\ region.\n#\ Extra\ regions\ can\ be\ used\ to\ create\ sensitive\ areas\ other\ pages\ can\ collect.\nWhen\ /someone/\ wishes\ /p/\ adds\ region\ with\ /...options/\ &\ /p/\ has\ region\ /r/\ \{\n\ \ lassign\ \[region\ centroid\ \$r\]\ cx\ cy\n\ \ set\ angle\ \[region\ angle\ \$r\]\n\n\ \ set\ defaults\ \{\n\ \ \ \ index\ 0\ \\\n\ \ \ \ height\ 55\ \\\n\ \ \ \ width\ 55\ \\\n\ \ \ \ highlight\ false\ \\\n\ \ \ \ color\ red\ \\\n\ \ \}\n\n\ \ set\ index\ \[dict\ get\ \$options\ index\]\n\ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ set\ highlight\ \[dict\ get\ \$options\ highlight\]\n\ \ set\ color\ \[dict\ get\ \$options\ color\]\n\n\ \ set\ offset\ \[dict_getdef\ \$options\ offset\ \{0\ 0\}\]\n\ \ set\ offset\ \[::process_offset\ \$offset\ \$r\]\n\ \ set\ center\ \[vec2\ add\ \[list\ \$cx\ \$cy\]\ \[vec2\ rotate\ \$offset\ \$angle\]\]\n\n\ \ #\ compute\ points\ offset\ from\ \$p\n\ \ set\ hw\ \[expr\ \{\$width\ /\ 2.0\}\]\n\ \ set\ hh\ \[expr\ \{\$height\ /\ 2.0\}\]\n\n\ \ #\ compute\ points\ in\ table\ coordinates\n\ \ set\ tablePoints\ \[lmap\ v\ \[list\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{\$hh\}\]\]\ \\\n\ \ \ \ \[list\ \[expr\ \{-\$hw\}\]\ \[expr\ \{-\$hh\}\]\]\ \\\n\ \ \]\ \{\n\ \ \ \ vec2\ add\ \$center\ \[vec2\ rotate\ \$v\ \$angle\]\ \n\ \ \}\]\n\n\ \ set\ edges\ \[list\]\n\ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$tablePoints\]\}\ \{incr\ i\}\ \{\n\ \ \ \ if\ \{\$i\ >\ 0\}\ \{\ lappend\ edges\ \[list\ \[expr\ \{\$i\ -\ 1\}\]\ \$i\]\ \}\n\ \ \}\n\ \ lappend\ edges\ \[list\ \[expr\ \{\[llength\ \$tablePoints\]\ -\ 1\}\]\ \[lindex\ \$tablePoints\ 0\]\]\n\n\ \ #\ Create\ new\ region\ in\ table\ points\n\ \ set\ indexedRegion\ \[region\ create\ \$tablePoints\ \$edges\ \$angle\]\n\ \ Claim\ \$p\ has\ indexedRegion\ with\ index\ \$index\ region\ \$indexedRegion\n\ \ Claim\ \"\$\{p\}:\$\{index\}\"\ has\ region\ \$indexedRegion\n\n\ \ #\ debug:\ display\ dashed\ line\ around\ the\ points\n\ \ if\ \{\$highlight\}\ \{\n\ \ \ \ Wish\ region\ \$indexedRegion\ has\ highlight\ \$highlight\ with\ color\ \$color\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ region\ /r/\ has\ highlight\ /highlighted/\ with\ /...options/\ \{\n\n\ \ set\ color\ \[dict_getdef\ \$options\ color\ white\]\n\ \ set\ thickness\ \[dict_getdef\ \$options\ thickness\ 2\]\n\ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\ \ set\ dashed\ \[dict_getdef\ \$options\ dashed\ false\]\n\ \ set\ dashlength\ \[dict_getdef\ \$options\ dashlength\ 20\]\n\ \ set\ dashoffset\ \[dict_getdef\ \$options\ dashoffset\ 0\]\n\n\ \ if\ \{\$highlighted\}\ \{\n\ \ \ \ set\ verts\ \[region\ vertices\ \$r\]\n\ \ \ \ set\ edges\ \[region\ edges\ \$r\]\n\ \ \ \ lappend\ verts\ \[lindex\ \$verts\ 0\]\n\ \ \ \ Wish\ to\ draw\ a\ dashed\ stroke\ with\ points\ \$verts\ color\ \$color\ width\ \$thickness\ dashlength\ \$dashlength\ dashoffset\ \$dashoffset\ layer\ \$layer\n\ \ \}\n\}\n\nClaim\ \$this\ has\ demo\ \{\n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n\}\n
<unknown> claims builtin-programs/display/arc.folk has program code #\ Example:\n#\ \ \ When\ \$this\ (
[ m168:0 (s256:0) ]
)<unknown> claims builtin-programs/display/arc.folk has program code #\ Example:\n#\ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ lassign\ \[region\ centroid\ \$r\]\ x\ y\n#\ \ \ \ \ Wish\ to\ draw\ an\ arc\ with\ x\ \$x\ y\ \$y\ start\ 0\ arclen\ 1\ thickness\ 3\ radius\ 100\ color\ green\n#\ \ \ \}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"arc\"\ \{\{vec2\ center\ float\ start\ float\ arclen\ float\ radius\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ float\ r\ =\ radius\ +\ thickness\;\n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ \ \ \ center\ -\ r,\n\ \ \ \ \ \ \ \ \ vec2(center.x\ +\ r,\ center.y\ -\ r),\n\ \ \ \ \ \ \ \ \ vec2(center.x\ -\ r,\ center.y\ +\ r),\n\ \ \ \ \ \ \ \ \ center\ +\ r\n\ \ \ \ )\;\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\}\ \{\n\ \ \ \ #define\ M_TWO_PI\ 6.283185307179586\n\ \ \ \ start\ =\ clamp(start,\ 0,\ M_TWO_PI)\;\n\ \ \ \ arclen\ =\ clamp(arclen,\ 0,\ M_TWO_PI)\;\n\n\ \ \ \ float\ dist\ =\ length(gl_FragCoord.xy\ -\ center)\ -\ radius\;\n\ \ \ \ float\ angle\ =\ atan(-(gl_FragCoord.y\ -\ center.y),\ gl_FragCoord.x\ -\ center.x)\;\n\n\ \ \ \ //\ Shift\ angle\ from\ \[-pi,\ pi)\ to\ \[0,\ 2*pi\]\n\ \ \ \ angle\ =\ (angle\ <\ 0)\ ?\ (angle\ +\ M_TWO_PI)\ :\ angle\;\n\ \ \ \ float\ end\ =\ start\ +\ arclen\;\n\n\ \ \ \ return\ ((dist\ <\ thickness\ &&\ dist\ >\ 0.0)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((end\ <\ M_TWO_PI\ &&\ angle\ >\ start\ &&\ angle\ <\ end)\ ||\ \n\ \ \ \ \ \ \ \ \ \ \ \ (end\ >=\ M_TWO_PI\ &&\ (angle\ >\ start\ ||\ angle\ <\ end-M_TWO_PI))))\ ?\ color\ :\ vec4(0,\ 0,\ 0,\ 0)\;\n\n\}\}\n\nWhen\ /someone/\ wishes\ to\ draw\ an\ arc\ with\ /...options/\ \{\n\ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"arc\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ \$x\ \$y\]\ \$start\ \$arclen\ \$radius\ \$thickness\ \[getColor\ \$color\]\]\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/display/curve.folk has program code \n#\ Bezier\ implementation\ fr (
[ m171:0 (s260:0) ]
)<unknown> claims builtin-programs/display/curve.folk has program code \n#\ Bezier\ implementation\ from\ https://www.shadertoy.com/view/XdVBWd\n\nWish\ the\ GPU\ compiles\ function\ \"bboxBezier\"\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\}\ vec4\ \{\n\ \ \ \ //\ Exact\ BBox\ to\ a\ quadratic\ bezier\n\ \ \ \ //\ extremes\n\ \ \ \ vec2\ mi\ =\ min(p0,p3)\;\n\ \ \ \ vec2\ ma\ =\ max(p0,p3)\;\n\n\ \ \ \ vec2\ k0\ =\ -1.0*p0\ +\ 1.0*p1\;\n\ \ \ \ vec2\ k1\ =\ \ 1.0*p0\ -\ 2.0*p1\ +\ 1.0*p2\;\n\ \ \ \ vec2\ k2\ =\ -1.0*p0\ +\ 3.0*p1\ -\ 3.0*p2\ +\ 1.0*p3\;\n\n\ \ \ \ vec2\ h\ =\ k1*k1\ -\ k0*k2\;\n\n\ \ \ \ if(\ h.x>0.0\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.x\ =\ sqrt(h.x)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.x\ -\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.x/(-k1.x-h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.x\ +\ h.x)/k2.x\;\n\ \ \ \ \ \ \ \ t\ =\ k0.x/(-k1.x+h.x)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.x\ +\ 3.0*s*s*t*p1.x\ +\ 3.0*s*t*t*p2.x\ +\ t*t*t*p3.x\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.x\ =\ min(mi.x,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.x\ =\ max(ma.x,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if(\ h.y>0.0)\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ h.y\ =\ sqrt(h.y)\;\n\ \ \ \ \ \ \ \ //float\ t\ =\ (-k1.y\ -\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ float\ t\ =\ k0.y/(-k1.y-h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ //t\ =\ (-k1.y\ +\ h.y)/k2.y\;\n\ \ \ \ \ \ \ \ t\ =\ k0.y/(-k1.y+h.y)\;\n\ \ \ \ \ \ \ \ if(\ t>0.0\ &&\ t<1.0\ )\n\ \ \ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ \ \ \ \ float\ q\ =\ s*s*s*p0.y\ +\ 3.0*s*s*t*p1.y\ +\ 3.0*s*t*t*p2.y\ +\ t*t*t*p3.y\;\n\ \ \ \ \ \ \ \ \ \ \ \ mi.y\ =\ min(mi.y,q)\;\n\ \ \ \ \ \ \ \ \ \ \ \ ma.y\ =\ max(ma.y,q)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \n\ \ \ \ return\ vec4(\ mi,\ ma\ )\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ sdSegmentSq\ \{\{vec2\ p\ vec2\ a\ vec2\ b\}\ float\ \{\n\ \ \ \ vec2\ pa\ =\ p-a,\ ba\ =\ b-a\;\n\ \ \ \ float\ h\ =\ clamp(\ dot(pa,ba)/dot(ba,ba),\ 0.0,\ 1.0\ )\;\n\ \ \ \ vec2\ d\ =\ pa\ -\ ba*h\;\n\ \ \ \ return\ dot(d,\ d)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ function\ udBezier\ \{\{vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ vec2\ pos\}\ vec2\ \{\n\ \ \ \ const\ int\ kNum\ =\ 50\;\n\ \ \ \ vec2\ res\ =\ vec2(1e10,0.0)\;\n\ \ \ \ vec2\ a\ =\ p0\;\n\ \ \ \ for(\ int\ i=1\;\ i<kNum\;\ i++\ )\n\ \ \ \ \{\n\ \ \ \ \ \ \ \ float\ t\ =\ float(i)/float(kNum-1)\;\n\ \ \ \ \ \ \ \ float\ s\ =\ 1.0-t\;\n\ \ \ \ \ \ \ \ vec2\ b\ =\ p0*s*s*s\ +\ p1*3.0*s*s*t\ +\ p2*3.0*s*t*t\ +\ p3*t*t*t\;\n\ \ \ \ \ \ \ \ float\ d\ =\ sdSegmentSq(\ pos,\ a,\ b\ )\;\n\ \ \ \ \ \ \ \ if(\ d<res.x\ )\ res\ =\ vec2(d,t)\;\n\ \ \ \ \ \ \ \ a\ =\ b\;\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ return\ vec2(sqrt(res.x),res.y)\;\n\}\}\n\nWish\ the\ GPU\ compiles\ pipeline\ \"curve\"\ \{\n\ \ \{\ vec2\ p0\ vec2\ p1\ vec2\ p2\ vec2\ p3\ float\ thickness\ vec4\ color\}\ \{\n\ \ \ \ //\ Need\ to\ calculate\ the\ bounds\ of\ the\ curve\n\ \ \ \ vec2\ from\ =\ min(min(p0,p1),min(p2,p3))\;\n\ \ \ \ vec2\ to\ =\ max(max(p0,p1),max(p2,p3))\;\n\ \ \ \ \n\ \ \ \ vec2\ vertices\[4\]\ =\ vec2\[4\](\n\ \ \ \ \ \ min(from,\ to)\ -\ thickness,\n\ \ \ \ \ \ vec2(max(from.x,\ to.x)\ +\ thickness,\ min(from.y,\ to.y)\ -\ thickness),\n\ \ \ \ \ \ vec2(min(from.x,\ to.x)\ -\ thickness,\ max(from.y,\ to.y)\ +\ thickness),\n\ \ \ \ \ \ max(from,\ to)\ +\ thickness\n\ \ \ \ )\;\n\n\ \ \ \ return\ vec4(vertices\[gl_VertexIndex\],\ 0.0,\ 1.0)\;\n\ \ \}\ \{fn\ sdSegmentSq\ fn\ udBezier\}\ \{\n\ \ \ \ vec2\ p\ =\ gl_FragCoord.xy\;\n\ \ \ \ float\ px\ =\ 2.0\;\ //\ sharpness\n\ \ \ \ float\ t\ =\ thickness\;\n\ \ \ \ float\ be\ =\ udBezier(\ p0,\ p1,\ p2,\ p3,\ p\ ).x\;\n\n\ \ \ \ float\ d\ =\ be\;\n\n\ \ \ \ vec4\ col\ =\ mix(\ vec4(0.0),\ color,\ 1.0-smoothstep(t,\ t\ +\ px*1.5,\ d)\ )\;\n\n\ \ \ \ //\ control\ points\n\ \ \ \ //d\ =\ length(p0-p)\;\ col\ =\ mix(\ col,\ vec4(1.0,\ 0.,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p1-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 1.0,\ 0.,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p2-p)\;\ col\ =\ mix(\ col,\ vec4(0.,\ 0.,\ 1.0,\ 1.),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\ \ \ \ //d\ =\ length(p3-p)\;\ col\ =\ mix(\ col,\ vec4(1.0),\ 1.0-smoothstep(4,4+px,d)\ )\;\n\n\ \ \ \ return\ col\;\n\ \ \}\n\}\n\nWhen\ /someone/\ wishes\ to\ draw\ a\ curve\ with\ /...options/\ \{\n\ \ \ \ set\ p0\ \ \[dict\ get\ \$options\ p0\]\n\ \ \ \ set\ p1\ \ \[dict\ get\ \$options\ p1\]\n\ \ \ \ set\ p2\ \ \[dict\ get\ \$options\ p2\]\n\ \ \ \ set\ p3\ \ \[dict\ get\ \$options\ p3\]\n\ \ \ \ set\ thickness\ \[dict\ get\ \$options\ thickness\]\n\ \ \ \ set\ color\ \[getColor\ \[dict\ get\ \$options\ color\]\]\n\ \ \ \ set\ layer\ \[dict_getdef\ \$options\ layer\ 0\]\n\n\ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"curve\"\ with\ arguments\ \\\n\ \ \ \ \ \ \ \ \[list\ \$p0\ \$p1\ \$p2\ \$p3\ \$thickness\ \$color\]\ \\\n\ \ \ \ \ \ \ \ layer\ \$layer\n\}\n
<unknown> claims builtin-programs/recognition/trocr.folk has program code When\ when\ the\ TrOCR\ tex (
[ m172:0 (s261:0) ]
)<unknown> claims builtin-programs/recognition/trocr.folk has program code When\ when\ the\ TrOCR\ text\ recognizer\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ TrOCR\ text\ recognizer\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ TrOCR\ text\ recognizer\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ transformers\ --with\ pillow\ --with\ torch\ --with\ protobuf\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ from\ transformers\ import\ TrOCRProcessor,\ VisionEncoderDecoderModel\n\ \ \ \ \ \ \ \ import\ os\n\ \ \ \ \ \ \ \ import\ sys\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ #\ Determine\ device\ (prefer\ CUDA\ >\ MPS\ >\ CPU)\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ #\ Load\ TrOCR\ model\n\ \ \ \ \ \ \ \ TROCR_PATH\ =\ os.path.expanduser(\"~/folk-data/trocr\")\n\ \ \ \ \ \ \ \ try:\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ disk.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ except\ Exception:\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Model\ not\ saved\;\ loading\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ \ \ \ \ processor\ =\ TrOCRProcessor.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ processor.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ model\ =\ VisionEncoderDecoderModel.from_pretrained(\"microsoft/trocr-base-handwritten\")\n\ \ \ \ \ \ \ \ \ \ \ \ model.save_pretrained(TROCR_PATH)\n\ \ \ \ \ \ \ \ \ \ \ \ print(\"trocr:\ Loaded\ TrOCR\ model\ from\ Internet.\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ model.to(device)\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ ocrImage\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ start_time\ =\ time.time()\n\n\ \ \ \ \ \ \ \ #\ Run\ TrOCR\ on\ the\ entire\ image\n\ \ \ \ \ \ \ \ with\ torch.no_grad():\n\ \ \ \ \ \ \ \ \ \ \ \ pixel_values\ =\ processor(image,\ return_tensors=\"pt\").pixel_values.to(device)\n\ \ \ \ \ \ \ \ \ \ \ \ generated_ids\ =\ model.generate(pixel_values)\n\ \ \ \ \ \ \ \ \ \ \ \ text\ =\ processor.batch_decode(generated_ids,\ skip_special_tokens=True)\[0\]\n\n\ \ \ \ \ \ \ \ elapsed\ =\ time.time()\ -\ start_time\n\ \ \ \ \ \ \ \ print(f\"trocr:\ Result:\ \{text\}\ (\{elapsed:.3f\}s)\",\ file=sys.stderr,\ flush=True)\n\n\ \ \ \ \ \ \ \ return\ text\n\ \ \ \ \}\n\n\ \ \ \ fn\ TrOCR\ \{im\}\ \{\ return\ \[\$py\ ocrImage\ \$im\]\ \}\n\ \ \ \ Claim\ the\ TrOCR\ text\ recognizer\ is\ \[fn\ TrOCR\]\n\}\n\n
<unknown> claims builtin-programs/recognition/sam2.folk has program code When\ when\ the\ SAM2\ segme (
[ m175:0 (s266:0) ]
)<unknown> claims builtin-programs/recognition/sam2.folk has program code When\ when\ the\ SAM2\ segmenter\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ SAM2\ segmenter\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ SAM2\ segmenter\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ torch\ --with\ numpy\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ huggingface_hub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ --with\ \"git+https://github.com/facebookresearch/sam2.git\"\]\n\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Boot\",\ file=sys.stderr)\n\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ import\ threading\n\ \ \ \ \ \ \ \ from\ sam2.sam2_image_predictor\ import\ SAM2ImagePredictor\n\ \ \ \ \ \ \ \ import\ sys\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Loading.\",\ file=sys.stderr)\n\ \ \ \ \ \ \ \ predictor\ =\ SAM2ImagePredictor.from_pretrained(\"facebook/sam2.1-hiera-small\",\ device=device)\n\ \ \ \ \ \ \ \ predictor_lock\ =\ threading.Lock()\n\ \ \ \ \ \ \ \ print(f\"sam2:\ Using\ device:\ \{device\}\",\ file=sys.stderr,\ flush=True)\n\ \ \ \ \}\n\n\ \ \ \ \$py\ def\ segment\ \{Image\ image\ \{list\ list\ num\}\ pointCoords\ \{list\ num\}\ pointLabels\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image.convert(\"RGB\"))\n\ \ \ \ \ \ \ \ with\ predictor_lock,\ torch.inference_mode():\n\ \ \ \ \ \ \ \ \ \ \ \ predictor.set_image(image_np)\n\ \ \ \ \ \ \ \ \ \ \ \ masks,\ scores,\ _\ =\ predictor.predict(\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_coords=pointCoords,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ point_labels=pointLabels,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ multimask_output=True,\n\ \ \ \ \ \ \ \ \ \ \ \ )\n\ \ \ \ \ \ \ \ best\ =\ int(scores.argmax())\n\ \ \ \ \ \ \ \ #\ Note:\ we\ spend\ 10-20ms\ just\ on\ serialization/deserialization\n\ \ \ \ \ \ \ \ #\ of\ the\ mask\ (it's\ basically\ a\ whole\ image).\n\ \ \ \ \ \ \ \ return\ \{\"mask\":\ masks\[best\].tolist(),\ \"score\":\ float(scores\[best\])\}\n\ \ \ \ \}\n\n\ \ \ \ fn\ SAM2\ args\ \{\ return\ \[\$py\ segment\ \{*\}\$args\]\ \}\n\ \ \ \ Claim\ the\ SAM2\ segmenter\ is\ \[fn\ SAM2\]\n\n\ \ \ \ When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ \ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \ \ \ \ \$cc\ proc\ maskToBinaryImage\ \{Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(width,\ height,\ 1,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\]\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \$cc\ proc\ applyMaskToImage\ \{Image\ im\ Jim_Obj*\ mask\}\ Image\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ height\ =\ Jim_ListLength(interp,\ mask)\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ width\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (height\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *firstRow\ =\ Jim_ListGetIndex(interp,\ mask,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ =\ Jim_ListLength(interp,\ firstRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Image\ result\ =\ imageNew(im.width,\ im.height,\ im.components,\ im.uniq)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ height\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *row\ =\ Jim_ListGetIndex(interp,\ mask,\ y)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ width\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj\ *elem\ =\ Jim_ListGetIndex(interp,\ row,\ x)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ val\;\ Jim_GetDouble(interp,\ elem,\ &val)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ m\ =\ val\ >\ 0.5\ ?\ 255\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ c\ =\ 0\;\ c\ <\ im.components\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ result.data\[y\ *\ result.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ =\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ m\ ?\ im.data\[y\ *\ im.bytesPerRow\ +\ x\ *\ im.components\ +\ c\]\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\ result\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ maskToImageLib\ \[\$cc\ compile\]\n\ \ \ \ \ \ \ \ Claim\ the\ SAM2\ mask-to-image\ library\ is\ \$maskToImageLib\n\ \ \ \ \}\n\}\n\n
<unknown> claims builtin-programs/recognition/craft.folk has program code When\ when\ the\ CRAFT\ tex (
[ m176:0 (s267:0) ]
)<unknown> claims builtin-programs/recognition/craft.folk has program code When\ when\ the\ CRAFT\ text\ detector\ is\ /any/\ /any/\ with\ environment\ /any/\ \{\n\ \ \ \ Wish\ -keep\ 500ms\ to\ load\ the\ CRAFT\ text\ detector\n\}\n\nWhen\ /someone/\ wishes\ to\ load\ the\ CRAFT\ text\ detector\ &\\\n\ \ \ \ \ the\ image\ uvx\ argtype\ definer\ is\ /defineImageArgtype/\ \{\n\ \ \ \ fn\ defineImageArgtype\n\n\ \ \ \ set\ py\ \[Uvx\ --with\ pillow\ --with\ \"git+https://github.com/osnr/craft-text-detector.git\"\]\n\ \ \ \ defineImageArgtype\ \$py\n\n\ \ \ \ \$py\ exec\ \{\n\ \ \ \ \ \ \ \ import\ torch\n\ \ \ \ \ \ \ \ import\ numpy\ as\ np\n\ \ \ \ \ \ \ \ from\ craft_text_detector\ import\ Craft\n\ \ \ \ \ \ \ \ import\ time\n\n\ \ \ \ \ \ \ \ if\ torch.cuda.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cuda\"\n\ \ \ \ \ \ \ \ elif\ torch.backends.mps.is_available():\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"mps\"\n\ \ \ \ \ \ \ \ else:\n\ \ \ \ \ \ \ \ \ \ \ \ device\ =\ \"cpu\"\n\n\ \ \ \ \ \ \ \ craft\ =\ Craft(output_dir=None,\ crop_type=\"box\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ link_threshold=0.1,\ device=device)\n\ \ \ \ \}\n\ \ \ \ \$py\ def\ detectTextBoxes\ \{Image\ image\}\ \{\n\ \ \ \ \ \ \ \ image_np\ =\ np.array(image)\n\n\ \ \ \ \ \ \ \ start_craft\ =\ time.time()\n\ \ \ \ \ \ \ \ result\ =\ craft.detect_text(image_np)\n\ \ \ \ \ \ \ \ boxes\ =\ result\[\"boxes\"\]\n\ \ \ \ \ \ \ \ craft_time\ =\ time.time()\ -\ start_craft\n\n\ \ \ \ \ \ \ \ print(f\"craft:\ Detected\ \{len(boxes)\}\ text\ boxes\ (\{craft_time:.3f\}s)\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ file=sys.stderr,\ flush=True)\n\ \ \ \ \ \ \ \ return\ boxes.tolist()\ if\ hasattr(boxes,\ 'tolist')\ else\ boxes\n\ \ \ \ \}\n\n\ \ \ \ fn\ CRAFT\ \{im\}\ \{\ return\ \[\$py\ detectTextBoxes\ \$im\]\ \}\n\ \ \ \ Claim\ the\ CRAFT\ text\ detector\ is\ \[fn\ CRAFT\]\n\}\n\n
<unknown> claims builtin-programs/recognition/contours.folk has program code When\ the\ image\ librar (
[ m179:0 (s271:0) ]
)<unknown> claims builtin-programs/recognition/contours.folk has program code When\ the\ image\ library\ is\ /imageLib/\ \{\n\ \ \ \ set\ cc\ \[C\]\n\ \ \ \ \$cc\ extend\ \$imageLib\n\ \ \ \ \$cc\ cflags\ -I.\n\ \ \ \ \$cc\ include\ \"vendor/CContour.c\"\n\n\ \ \ \ #\ Binarizes\ the\ first\ channel\ of\ `im`\ at\ `threshold`\ and\ returns\n\ \ \ \ #\ the\ contours\ as\ a\ Tcl\ list.\ Each\ contour\ is\ itself\ a\ Tcl\ list\ of\n\ \ \ \ #\ \{x\ y\}\ pairs.\ If\ epsilon\ >\ 0,\ each\ contour\ is\ simplified\ with\n\ \ \ \ #\ Ramer-Douglas-Peucker.\n\ \ \ \ #\n\ \ \ \ #\ Contours\ are\ scaled\ by\ `scaleX`\ and\ `scaleY`\ so\ that\ they\ can\ be\n\ \ \ \ #\ returned\ in\ real-world\ meters\ (instead\ of\ image-pixel\ space).\n\ \ \ \ #\n\ \ \ \ #\ Discards\ any\ contours\ that\ are\ not\ at\ least\ minLength\ long\n\ \ \ \ #\ (unless\ minLength\ is\ very\ small).\n\ \ \ \ \$cc\ proc\ findImageContours\ \{Image\ im\ int\ threshold\ double\ epsilon\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ scaleX\ double\ scaleY\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ minLength\}\ Jim_Obj*\ \{\n\ \ \ \ \ \ \ \ int\ w\ =\ (int)im.width\;\n\ \ \ \ \ \ \ \ int\ h\ =\ (int)im.height\;\n\ \ \ \ \ \ \ \ if\ (w\ <\ 3\ ||\ h\ <\ 3)\ return\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\n\ \ \ \ \ \ \ \ int\ *F\ =\ malloc(sizeof(int)\ *\ (size_t)w\ *\ (size_t)h)\;\n\ \ \ \ \ \ \ \ for\ (int\ y\ =\ 0\;\ y\ <\ h\;\ y++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uint8_t\ *row\ =\ im.data\ +\ (size_t)y\ *\ im.bytesPerRow\;\n\ \ \ \ \ \ \ \ \ \ \ \ int\ *Frow\ =\ F\ +\ (size_t)y\ *\ w\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (int\ x\ =\ 0\;\ x\ <\ w\;\ x++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Frow\[x\]\ =\ (row\[x\ *\ im.components\]\ >\ threshold)\ ?\ 1\ :\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Contour\ *contours\ =\ findContours(F,\ w,\ h)\;\n\ \ \ \ \ \ \ \ free(F)\;\n\n\ \ \ \ \ \ \ \ Jim_Obj\ *outer\ =\ Jim_NewListObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \ \ \ \ for\ (ptrdiff_t\ c\ =\ 0\;\ c\ <\ arrlen(contours)\;\ c++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Point\ *pts\ =\ (epsilon\ >\ 0)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ?\ approxPolyDP(contours\[c\].points,\ (float)epsilon)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ :\ contours\[c\].points\;\n\ \ \ \ \ \ \ \ \ \ \ \ ptrdiff_t\ n\ =\ arrlen(pts)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (minLength\ >\ 0.0001)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ total\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 1\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dx\ =\ (pts\[k\].x\ -\ pts\[k-1\].x)\ *\ scaleX\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ double\ dy\ =\ (pts\[k\].y\ -\ pts\[k-1\].y)\ *\ scaleY\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ total\ +=\ sqrt(dx*dx\ +\ dy*dy)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (total\ <\ minLength)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ %g\ prints\ up\ to\ ~13\ chars\ per\ double\;\ round\ up\ to\ give\ headroom.\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ cap\ =\ (size_t)n\ *\ 40\ +\ 1\;\n\ \ \ \ \ \ \ \ \ \ \ \ char\ *buf\ =\ malloc(cap)\;\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ off\ =\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (ptrdiff_t\ k\ =\ 0\;\ k\ <\ n\;\ k++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ off\ +=\ snprintf(buf\ +\ off,\ cap\ -\ off,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\ ==\ 0\ ?\ \"\{%g\ %g\}\"\ :\ \"\ \{%g\ %g\}\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pts\[k\].x\ *\ scaleX,\ pts\[k\].y\ *\ scaleY)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ Jim_NewStringObjNoAlloc\ takes\ ownership\ of\ buf.\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_ListAppendElement(interp,\ outer,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Jim_NewStringObjNoAlloc(interp,\ buf,\ (int)off))\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (epsilon\ >\ 0)\ arrfree(pts)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ freeContours(contours)\;\n\ \ \ \ \ \ \ \ return\ outer\;\n\ \ \ \ \}\n\n\ \ \ \ set\ contourLib\ \[\$cc\ compile\]\n\ \ \ \ Claim\ the\ contour\ library\ is\ \$contourLib\n\}\n\nWhen\ /someone/\ wishes\ /p/\ has\ contours\ \{\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ _\ \{\}\n\}\nWhen\ the\ contour\ library\ is\ /contourLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ contours\ with\ /...opts/\ \{\n\ \ \ \ Wish\ \$p\ has\ camera\ slice\n\ \ \ \ When\ \$p\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ \$p\ has\ camera\ slice\ /s/\ \{\n\ \ \ \ \ \ \ \ set\ scaleX\ \[/\ \$geom(width)\ \$s(width)\]\n\ \ \ \ \ \ \ \ set\ scaleY\ \[/\ \$geom(height)\ \$s(height)\]\n\ \ \ \ \ \ \ \ set\ threshold\ \[dict\ getdef\ \$opts\ threshold\ 128\]\n\ \ \ \ \ \ \ \ set\ epsilon\ \[dict\ getdef\ \$opts\ epsilon\ 3.0\]\n\ \ \ \ \ \ \ \ set\ minLength\ \[dict\ getdef\ \$opts\ minLength\ 0.0\]\n\ \ \ \ \ \ \ \ Claim\ \$p\ has\ contours\ \[\$contourLib\ findImageContours\ \$s\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$threshold\ \$epsilon\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$scaleX\ \$scaleY\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$minLength\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ \{*\}\$opts\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/saving/save-holds.folk has program code set\ cc\ \[C\]\n\n\$cc\ inc (
[ m181:0 (s275:0) ]
)<unknown> claims builtin-programs/saving/save-holds.folk has program code set\ cc\ \[C\]\n\n\$cc\ include\ <pthread.h>\n\$cc\ include\ <assert.h>\n\$cc\ include\ <stdio.h>\n\$cc\ include\ <string.h>\n\$cc\ include\ \"jim.h\"\n\n\$cc\ code\ \{\n\n/*\ Generic\ string\ hash\ function\ from\ jim.c\ */\nstatic\ unsigned\ int\ cacheGenHashFunction(const\ unsigned\ char\ *string,\ int\ length)\ \{\n\ \ \ \ unsigned\ result\ =\ 0\;\n\ \ \ \ string\ +=\ length\;\n\ \ \ \ while\ (length--)\ \{\n\ \ \ \ \ \ \ \ result\ +=\ (result\ <<\ 3)\ +\ (unsigned\ char)(*--string)\;\n\ \ \ \ \}\n\ \ \ \ return\ result\;\n\}\nstatic\ unsigned\ int\ holdHTHashFunction(const\ void\ *key)\ \{\n\ \ \ \ return\ cacheGenHashFunction(key,\ strlen(key))\;\n\}\nstatic\ void\ *holdHTKeyDup(void\ *privdata,\ const\ void\ *key)\ \{\n\ \ \ \ return\ strdup(key)\;\n\}\nstatic\ void\ *holdHTValDup(void\ *privdata,\ const\ void\ *val)\ \{\n\ \ \ \ return\ strdup(val)\;\n\}\nstatic\ int\ holdHTKeyCompare(void\ *privdata,\ const\ void\ *key1,\ const\ void\ *key2)\ \{\n\ \ \ \ return\ strcmp(key1,\ key2)\ ==\ 0\;\n\}\nstatic\ void\ holdHTKeyDestructor(void\ *privdata,\ void\ *key)\ \{\n\ \ \ \ free(key)\;\n\}\nstatic\ void\ holdHTValDestructor(void\ *privdata,\ void\ *val)\ \{\n\ \ \ \ free(val)\;\n\}\n\nstatic\ const\ Jim_HashTableType\ holdHashTableType\ =\ \{\n\ \ \ \ .hashFunction\ =\ holdHTHashFunction,\n\ \ \ \ .keyDup\ =\ holdHTKeyDup,\n\ \ \ \ .valDup\ =\ holdHTValDup,\n\ \ \ \ .keyCompare\ =\ holdHTKeyCompare,\n\ \ \ \ .keyDestructor\ =\ holdHTKeyDestructor,\n\ \ \ \ .valDestructor\ =\ holdHTValDestructor\n\}\;\n\n//\ key\ =\ value\ of\ -on\ passed\ to\ Hold!,\n//\ val\ =\ string\ that\ can\ be\ converted\ to\ a\ jim\ dict,\ with\n//\ that\ dict\ having\ its\ key\ =\ the\ value\ passed\ to\ -key\n//\ and\ its\ value\ =\ its\ corresponding\ held\ statement\nstatic\ Jim_HashTable\ holds\;\nstatic\ int\ areHoldsInitialized\ =\ 0\;\n\nstatic\ pthread_mutex_t\ holdMutex\ =\ PTHREAD_MUTEX_INITIALIZER\;\n\n\}\n\n\$cc\ proc\ init\ \{\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ if\ (!areHoldsInitialized)\ \{\n\ \ \ \ \ \ \ \ areHoldsInitialized\ =\ 1\;\n\ \ \ \ \ \ \ \ Jim_InitHashTable(&holds,\ &holdHashTableType,\ interp)\;\n\ \ \ \ \}\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n\$cc\ proc\ loadHolds\ \{char*\ canonicalName\ char*\ holdStr\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonicalName,\ (void\ *)holdStr)\;\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\}\n\n#\ canonical,\ tclEscaped,\ and\ filename\ all\ have\ to\ do\ with\ the\ value\ from\ -on\ in\ Hold!\n\$cc\ proc\ saveHold\ \{char*\ canonical\ Jim_Obj*\ tclEscaped\ char*\ filename\ Jim_Obj*\ key\ Jim_Obj*\ clause\}\ void\ \{\n\ \ \ \ pthread_mutex_lock(&holdMutex)\;\n\ \ \ \ assert(areHoldsInitialized)\;\n\n\ \ \ \ Jim_Obj*\ holdDict\ =\ NULL\;\n\n\ \ \ \ Jim_HashEntry*\ he\ =\ Jim_FindHashEntry(&holds,\ canonical)\;\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ //\ this\ is\ this\ files'\ first\ hold\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewDictObj(interp,\ NULL,\ 0)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ holdDict\ =\ Jim_NewStringObj(interp,\ (char\ *)Jim_GetHashEntryVal(he),\ -1)\;\n\ \ \ \ \}\n\n\ \ \ \ //\ empty\ clause,\ e.g.\ removal\n\ \ \ \ if\ (Jim_Length(clause)\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ NULL)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_DictAddElement(interp,\ holdDict,\ key,\ clause)\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (he\ ==\ NULL)\ \{\n\ \ \ \ \ \ \ \ Jim_AddHashEntry(&holds,\ (const\ void\ *)canonical,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ Jim_SetHashVal(&holds,\ he,\ (void\ *)Jim_String(holdDict))\;\n\ \ \ \ \}\n\n\ \ \ \ pthread_mutex_unlock(&holdMutex)\;\n\n\ \ \ \ //\ grab\ entries\ from\ dict\n\ \ \ \ int\ dictLen\ =\ 0\;\n\ \ \ \ Jim_Obj**\ dictValues\ =\ Jim_DictPairs(interp,\ holdDict,\ &dictLen)\;\n\n\ \ \ \ if\ (dictLen\ >\ 0)\ \{\n\ \ \ \ \ \ \ \ //\ write\ changes\n\ \ \ \ \ \ \ \ FILE*\ file\ =\ fopen(filename,\ \"w+b\")\;\n\ \ \ \ \ \ \ \ assert(file\ !=\ NULL)\;\n\n\ \ \ \ \ \ \ \ //\ write\ the\ filename\ in\ tcl\ form\ at\ the\ top\ of\ the\ file\n\ \ \ \ \ \ \ \ fwrite(Jim_String(tclEscaped),\ 1,\ Jim_Length(tclEscaped),\ file)\;\n\ \ \ \ \ \ \ \ fwrite(\"\\n\\n\",\ 1,\ 2,\ file)\;\n\n\ \ \ \ \ \ \ \ //\ write\ all\ hash\ entries,\ with\ one\ entry\ per\ line\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ dictLen\;\ i\ +=\ 2)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ pair\[\]\ =\ \{\ dictValues\[i\],\ dictValues\[i\ +\ 1\]\ \}\;\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_Obj*\ tmpListObj\ =\ Jim_NewListObj(interp,\ pair,\ 2)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(Jim_String(tmpListObj),\ 1,\ Jim_Length(tmpListObj),\ file)\;\n\ \ \ \ \ \ \ \ \ \ \ \ fwrite(\"\\n\",\ 1,\ 1,\ file)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ Jim_FreeNewObj(interp,\ tmpListObj)\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ fclose(file)\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ //\ the\ dict\ is\ empty,\ so\ we\ should\ delete\ its\ hold\ file\ if\ it\ exists\n\ \ \ \ \ \ \ \ remove(filename)\;\ //\ no\ need\ to\ check\ error\n\ \ \ \ \}\n\n\ \ \ \ Jim_FreeNewObj(interp,\ holdDict)\;\n\}\n\nset\ savedHoldsLib\ \[\$cc\ compile\]\n\$savedHoldsLib\ init\n\nWhen\ /someone/\ wishes\ to\ deserialize\ namespace\ hold\ with\ directory\ /directory/\ \{\n\ \ \ \ set\ holdFiles\ \[glob\ -nocomplain\ \$directory/*\]\n\n\ \ \ \ foreach\ holdFile\ \$holdFiles\ \{\n\ \ \ \ \ \ \ \ set\ fd\ \[open\ \$holdFile\ r\]\n\ \ \ \ \ \ \ \ set\ holds\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ #\ the\ hold\ file's\ first\ line\ is\ its\ canonical\ name\ (since\n\ \ \ \ \ \ \ \ #\ having\ /\ in\ a\ filename\ would\ mess\ a\ lot\ of\ stuff\ up),\n\ \ \ \ \ \ \ \ #\ while\ the\ rest\ of\ the\ file\ is\ a\ dict\ of\ holds\n\ \ \ \ \ \ \ \ set\ canonicalName\ \[lindex\ \$holds\ 0\]\n\ \ \ \ \ \ \ \ set\ holdDict\ \[lrange\ \$holds\ 1\ end\]\n\n\ \ \ \ \ \ \ \ dict\ for\ \{key\ clause\}\ \$holdDict\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ \$canonicalName\ -key\ \$key\ --\ \{*\}\$clause\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ loadHolds\ \$canonicalName\ \$holdDict\n\ \ \ \ \}\n\n\ \ \ \ Claim\ the\ saved\ holds\ are\ loaded\n\}\n\nWhen\ the\ hold\ save\ directory\ is\ /holdDirectory/\ \{\n\ \ \ \ Subscribe:\ save\ hold\ on\ /on/\ with\ key\ /key/\ clause\ /clause/\ \{\n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ \}\n\n\ \ \ \ Claim\ saving\ is\ ready\n\}\n
<unknown> claims builtin-programs/saving/migrate.folk has program code When\ the\ hold\ save\ directo (
[ m182:0 (s277:0) ]
)<unknown> claims builtin-programs/saving/migrate.folk has program code When\ the\ hold\ save\ directory\ is\ /holdDirectory/\ &\\\n\ \ \ \ \ the\ program\ save\ directory\ is\ /programDirectory/\ &\\\n\ \ \ \ \ saving\ is\ ready\ \{\n\n\ \ \ \ #\ HACK:\ A\ new\ migration\ we\ put\ here\ so\ it\ precedes\ Hold\ load:\n\ \ \ \ #\ remove\ incompatible\ old\ editor\ data\ (new\ editor\ data\ will\ be\n\ \ \ \ #\ stored\ with\ respect\ to\ editor/editor.folk,\ not\ editor.folk).\n\ \ \ \ #\ Old\ editor\ data\ is\ incompatible.\n\ \ \ \ file\ delete\ \$::env(HOME)/folk-data/hold/editor.folk\n\n\ \ \ \ #\ are\ we\ already\ on\ the\ new\ format?\n\ \ \ \ if\ \{\[llength\ \[glob\ -nocomplain\ \$::env(HOME)/folk-data/hold/*\]\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ #\ is\ this\ a\ brand\ new\ system?\n\ \ \ \ if\ \{!\[file\ exists\ \"\$::env(HOME)/folk-live\"\]\ &&\ !\[file\ exists\ \"\$::env(HOME)/folk-printed-programs\"\]\}\ \{\n\ \ \ \ \ \ \ \ Claim\ this\ is\ a\ first\ boot\n\ \ \ \ \ \ \ \ Claim\ the\ migration\ is\ complete\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryReadFile\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ set\ contents\ \"\"\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ rb\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contents\ \[read\ \$fd\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ \ \ \ \ return\ \$contents\n\ \ \ \ \}\n\n\ \ \ \ proc\ tryRm\ \{filename\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ exec\ rm\ \$filename\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\n\ \ \ \ #\ copy\ programs\ to\ new\ location\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ exec\ sh\ <<\ \"cp\ ~/folk-printed-programs/*\ ~/folk-data/program/\"\n\ \ \ \ \}\ on\ error\ e\ \{\}\n\n\ \ \ \ #\ grab\ geometry\ before\ deleting\n\ \ \ \ set\ defaultGeom\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\]\n\ \ \ \ if\ \{\$defaultGeom\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ default-program-geometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ default\ program\ geometry\ is\ \$defaultGeom\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/default.folkgeom\"\n\n\ \ \ \ #\ also\ grab\ next\ id\n\ \ \ \ set\ nextId\ \[tryReadFile\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\]\n\ \ \ \ if\ \{\$nextId\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \[string\ trim\ \$nextId\]\n\ \ \ \ \}\n\ \ \ \ tryRm\ \"\$::env(HOME)/folk-data/program/next-id.txt\"\n\n\ \ \ \ #\ transfer\ calibration\n\ \ \ \ set\ calibrationPoses\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-poses.txt\"\]\n\ \ \ \ set\ calibration\ \[tryReadFile\ \"\$::env(HOME)/folk-live/folk-calibration-output.txt\"\]\n\ \ \ \ if\ \{\$calibrationPoses\ !=\ \"\"\ &&\ \$calibration\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ calibration\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ is\ \$calibration\n\ \ \ \ \ \ \ \ Hold!\ -save\ -on\ calibration\ -key\ poses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ calibration\ poses\ are\ \$calibrationPoses\n\ \ \ \ \}\n\n\ \ \ \ puts\ \"\\n\\n\\n###\ MIGRATION\ SUCCESSFUL\ ###\\n\"\n\ \ \ \ puts\ \"Note:\ folk-printed-programs/\ and\ folk-live/\ are\ no\ longer\ needed.\ \\\nFeel\ free\ to\ delete\ them\ once\ you've\ confirmed\ that\ everything\ works!\"\n\ \ \ \ puts\ \"\\n############################\\n\\n\\n\"\n\n\ \ \ \ Claim\ the\ migration\ is\ complete\n\}\n
<unknown> claims builtin-programs/saving/saving.folk has program code set\ dataDirectory\ \"\$::env(H (
[ m183:0 (s281:0) ]
)<unknown> claims builtin-programs/saving/saving.folk has program code set\ dataDirectory\ \"\$::env(HOME)/folk-data\"\n\nif\ \{!\[file\ isdirectory\ \$dataDirectory\]\}\ \{\n\ \ \ \ file\ mkdir\ \$dataDirectory\n\}\n\n#\ make\ sure\ the\ migration\ happens\ before\ loading\ everything,\n#\ so\ we\ load\ in\ the\ migrated\ data\nWhen\ the\ migration\ is\ complete\ \{\n\ \ \ \ set\ namespaces\ \[glob\ -nocomplain\ \$dataDirectory/*/\]\n\n\ \ \ \ foreach\ namespace\ \$namespaces\ \{\n\ \ \ \ \ \ \ \ set\ namespaceName\ \[file\ tail\ \$namespace\]\n\ \ \ \ \ \ \ \ Wish\ to\ deserialize\ namespace\ \$namespaceName\ with\ directory\ \$namespace\n\ \ \ \ \}\n\}\n\nWhen\ when\ the\ /fileType/\ save\ directory\ is\ /anything/\ \\\n\ \ \ \ \ \ \ \ \ \ /body/\ with\ environment\ /e/\ \{\n\ \ \ \ set\ serdeDirectory\ \"\$dataDirectory/\$fileType\"\n\n\ \ \ \ #\ make\ sure\ directory\ exists\n\ \ \ \ file\ mkdir\ \$serdeDirectory\n\n\ \ \ \ Claim\ the\ \$fileType\ save\ directory\ is\ \$serdeDirectory\n\}\n
<unknown> claims builtin-programs/saving/save-programs.folk has program code When\ this\ is\ a\ first (
[ m186:0 (s282:0) ]
)<unknown> claims builtin-programs/saving/save-programs.folk has program code When\ this\ is\ a\ first\ boot\ \{\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ 0\n\}\n
<unknown> claims builtin-programs/editor/editor.folk has program code #\ This\ makes\ all\ keyboards\ (
[ m189:0 (s288:0) ]
)<unknown> claims builtin-programs/editor/editor.folk has program code #\ This\ makes\ all\ keyboards\ create\ editors\ automatically.\ May\ choose\ to\n#\ change\ later,\ or\ exclude\ keyboards\ that\ opt\ out.\nWhen\ /k/\ is\ a\ keyboard\ with\ /...opts/\ \{\n\ \ \ \ Wish\ tag\ \$k\ is\ stabilized\n\n\ \ \ \ When\ \$k\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ When\ /nobody/\ claims\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Create\ a\ synthetic\ editor\ on\ top\ of\ the\ program\ being\ edited,.\n\ \ \ \ \ \ \ \ \ \ \ \ set\ editor\ \[list\ \$k\ editor\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ is\ an\ editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ has\ a\ canvas\ with\ layer\ 98\n\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$editor\ has\ resolved\ geometry\ \$geom\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ quad\ /q/\ \{\ Claim\ \$editor\ has\ quad\ \$q\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ has\ created\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$editor\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ When\ \$program\ is\ an\ editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ \$k\ is\ typing\ into\ \$program\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ program\ save\ directory\ is\ /programDir/\ &\\\n\ \ \ \ \ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ TODO:\ also\ don't\ hardcode\ this?\nset\ defaults\ \{\ textScale\ 0.01\ \}\nWhen\ /someone/\ claims\ /editor/\ is\ an\ editor\ \{\n\ \ \ \ Claim\ \$editor\ is\ an\ editor\ with\ \{*\}\$defaults\n\ \ \ \ When\ /nobody/\ has\ created\ editor\ \$editor\ &\\\n\ \ \ \ \ \ \ \ \ \$editor\ points\ up\ with\ length\ 0.3\ at\ /program/\ \{\n\ \ \ \ \ \ \ \ Wish\ tag\ \$editor\ is\ stabilized\n\ \ \ \ \ \ \ \ Wish\ tag\ \$program\ is\ stabilized\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selected\ program\ \$program\n\ \ \ \ \}\n\}\n\nWhen\ /editor/\ is\ an\ editor\ with\ /...options/\ \{\n\ \ \ \ #\ HACK:\ because\ we\ partial\ match\n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ options\ \[dict\ merge\ \$defaults\ \$options\]\n\ \ \ \ #\ CSS\ order:\ top,\ right,\ bottom,\ left.\ If\ the\ program's\ geometry\n\ \ \ \ #\ carries\ printed-page\ margins,\ prefer\ those\ so\ the\ editor\ draws\n\ \ \ \ #\ text\ at\ the\ same\ offsets\ it\ was\ printed\ at\;\ otherwise\ fall\ back\n\ \ \ \ #\ to\ the\ default.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ marginTop\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginTop\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginRight\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginBottom\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$geom\ marginLeft\]\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ margin\ \[list\ 0.01\ 0.005\ 0.005\ 0.01\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Initial\ setup\n\ \ \ \ #\ Load\ initial\ text\ settings\ if\ not\ set\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /nobody/\ claims\ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ /...anything/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Wait\ until\ all\ the\ saved\ holds\ are\ loaded,\ so\ we\ don't\ accidentally\n\ \ \ \ \ \ \ \ #\ overwrite\ a\ saved\ setting.\n\ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$options\ textScale\]\n\ \ \ \ \ \ \ \ #\ If\ the\ program's\ geometry\ carries\ a\ lineHeight\ (printed-page\n\ \ \ \ \ \ \ \ #\ metadata),\ prefer\ that\ over\ the\ global\ default\ so\ the\ editor\n\ \ \ \ \ \ \ \ #\ opens\ at\ the\ same\ scale\ the\ program\ was\ printed\ at.\n\ \ \ \ \ \ \ \ set\ geomResults\ \[Query!\ \$editor\ has\ resolved\ geometry\ /geom/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$geomResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ geom\ \[dict\ get\ \[lindex\ \$geomResults\ 0\]\ geom\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$geom\ lineHeight\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$geom\ lineHeight\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \}\n\n\ \ \ \ #\ We\ need\ the\ editor's\ resolved\ geometry\ to\ get\ its\ size.\n\ \ \ \ #\ We\ then\ use\ its\ size\ to\ figure\ out\ how\ many\ characters\ we\ can\ fit\ in\ it,\n\ \ \ \ #\ width-wise\ and\ height-wise.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ /program/\ has\ font\ options\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ size\ \[\$utils\ editorSizeInCharacters\ \$margin\ \$geom\ \$options\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ defaults\ for\ the\ editor\ if\ it\ hasn't\ been\ initialized\n\ \ \ \ set\ results\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ cursor\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ 0\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ clipResults\ \[Query!\ /somebody/\ claims\ editor\ \$editor\ has\ clipboard\ /anything/\]\n\ \ \ \ if\ \{\[llength\ \$clipResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \"\"\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ in\ initial\ program\ code\ (note,\ this\ buffer\ is\ shared\ between\n\ \ \ \ #\ all\ editor\ instances)\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ /program/\ has\ program\ code\ /programCode/\ &\\\n\ \ \ \ \ \ \ \ \ the\ saved\ holds\ are\ loaded\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ the\ code\ already\ exists.\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ editor\ buffer\ for\ \$program\ is\ /anything/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$programCode\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ keyboard\ /keyboard/\ claims\ key\ Control_b\ is\ down\ with\ /...options/\ \{\n\ \ \ \ Notify:\ print\ code\ \"#\ blank\"\n\}\n\nWhen\ /keyboard/\ is\ a\ keyboard\ with\ path\ /kbPath/\ /...anything/\ &\\\n\ \ \ \ \ /keyboard/\ is\ typing\ into\ /editor/\ &\\\n\ \ \ \ \ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ Subscribe:\ keyboard\ \$kbPath\ claims\ key\ /key/\ is\ /keyState/\ with\ /...options/\ \{\n\ \ \ \ \ \ \ \ ForEach!\ editor\ \$editor\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ \$program\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ max\ cursor\ x\ /maxCursorX/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ clipboard\ /clipboard/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ undo\ stack\ /undoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ redo\ stack\ /redoStack/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ last\ edit\ type\ /lastEditType/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$keyState\ ==\ \"up\"\}\ \{\ return\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ if\ this\ is\ true,\ the\ buffer\ will\ remove\ the\ hold\ for\ program\ code\n\ \ \ \ \ \ \ \ \ \ \ \ #\ (triggering\ a\ reinitialization)\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ false\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCode\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origCursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ set\ origMaxCursorX\ \$maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hasShift\ \[dict\ exists\ \$options\ shift\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ isNavKey\ \[expr\ \{\$key\ eq\ \"Left\"\ ||\ \$key\ eq\ \"Right\"\ ||\ \$key\ eq\ \"Up\"\ ||\ \$key\ eq\ \"Down\"\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ selection\ replacement\ for\ text-modifying\ keys\n\ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ false\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selectionHandled\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Return\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Delete\ selection,\ then\ fall\ through\ to\ Return\ handler\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\$selectionHandled\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$hasShift\ &&\ \$isNavKey\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Shift+Arrow:\ extend\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ eq\ \"\"\}\ \{\ set\ selAnchor\ \$cursor\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ insertText\ \$code\ \$cursor\ \[dict\ get\ \$options\ printable\]\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Regular\ navigation\ clears\ selection\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$isNavKey\}\ \{\ set\ selAnchor\ \"\"\ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ general\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleNavigation\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ handleRemovalAndReturn\ \$key\ \$code\ \$cursor\ \$maxCursorX\]\ code\ cursor\ maxCursorX\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ specific\ editor\ functionality\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ switch\ \$key\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_c\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_x\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ clipText\ \[\$utils\ getSelectedText\ \$code\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ clipboard-of:\$editor\ Claim\ editor\ \$editor\ has\ clipboard\ \$clipText\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \"\"\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_v\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$clipboard\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$selStart\ \$selEnd\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ replaceRange\ \$code\ \$cursor\ \$cursor\ \$clipboard\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_z\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ redoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$undoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isUndo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_y\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$redoStack\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$code\ \$cursor\ \$maxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$redoStack\ end\]\ code\ cursor\ maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \[lrange\ \$redoStack\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ isRedo\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_r\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ resetBuffer\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_s\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ save\ code\ on\ editor\ \$editor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_p\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ program\ from\ editor\ \$editor\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Printing!\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ printing-alert:\$editor\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Control_underscore\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ -\ (zoom\ out)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[/\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ equal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Dunno\ why\ it\ registers\ as\ equal\ instead\ of\ Control_equal?\ It\ works\ regardless,\ lol\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ ctrl\ and\ +\ (zoom\ in)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ textScale\ \[*\ \$textScale\ 1.1\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ font-options-of:\$editor:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ scale\ \$textScale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ stack\ management\ with\ coalescing\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ne\ \$origCode\ &&\ !\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Determine\ edit\ type\ for\ coalescing\ consecutive\ same-type\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"insert\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{\$key\ eq\ \"Delete\"\ ||\ \$key\ eq\ \"Remove\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"delete\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ editType\ \"other\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Only\ push\ when\ edit\ type\ changes\ or\ for\ non-coalescable\ edits\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$editType\ ne\ \$lastEditType\ ||\ \$editType\ eq\ \"other\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ undoStack\ \[list\ \$origCode\ \$origCursor\ \$origMaxCursorX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$undoStack\]\ >\ 50\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \[lrange\ \$undoStack\ end-49\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \$editType\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Any\ real\ edit\ clears\ the\ redo\ stack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ elseif\ \{!\$isUndo\ &&\ !\$isRedo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Navigation\ or\ no-op\ resets\ edit\ type\ (breaks\ coalescing)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$resetBuffer\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cursor\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ maxCursorX\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ selAnchor\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ undoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ redoStack\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lastEditType\ \"\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ remove\ the\ edited\ code\ to\ restore\ the\ program\ to\ its\ original\ code\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \{\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ file\ delete\ \"\$programDir/\[regsub\ \{\\.folk\$\}\ \$program\ \{\}\].folk.edited\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ When\ \$program\ has\ program\ code\ /originalCode/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$originalCode\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -save\ -key\ buffer-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ buffer\ for\ \$program\ is\ \$code\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Be\ sure\ to\ have\ at\ least\ two\ characters\ on\ the\ left,\ so\ we\ can\n\ \ \ \ \ \ \ \ \ \ \ \ #\ see\ what\ we're\ removing.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[-\ \$cursorX\ 2\]\ <\ \$vpX\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \[max\ 0\ \[-\ \$cursorX\ 2\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorX\ >=\ \$vpX\ +\ \$vpWidth\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpX\ \$(\$cursorX\ -\ \$vpWidth)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ <\ \$vpY\}\ \{\ set\ vpY\ \$cursorY\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorY\ >=\ \$vpY\ +\ \$vpHeight\ -\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vpY\ \$(\$cursorY\ -\ \$vpHeight\ +\ 1)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -keep\ 12ms\ -key\ editor-state-of:\$editor\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ viewport\ position\ \[list\ \$vpX\ \$vpY\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ \$cursor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ max\ cursor\ x\ \$maxCursorX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ selection\ anchor\ \$selAnchor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ undo\ stack\ \$undoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ redo\ stack\ \$redoStack\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ editor\ \$editor\ has\ last\ edit\ type\ \$lastEditType\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nSubscribe:\ save\ code\ on\ editor\ /editor/\ \{\n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n\}\n\n#\ calculate\ cursor\ position\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...textOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\n\ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$cursor\]\ cursorX\ cursorY\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$textOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ set\ offsetX\ \$((\$cursorX\ -\ \$vpX)\ *\ \$advance)\n\ \ \ \ set\ offsetY\ \$((\$cursorY\ -\ \$vpY)\ *\ \$textScale)\n\n\ \ \ \ Claim\ editor\ \$editor\ has\ cursor\ position\ \[list\ \$offsetX\ \$offsetY\]\n\}\n\n\}\n
<unknown> claims builtin-programs/editor/print-editor.folk has program code fn\ editorToPrintOptions\ (
[ m190:0 (s287:0) ]
)<unknown> claims builtin-programs/editor/print-editor.folk has program code fn\ editorToPrintOptions\ \{editor\}\ \{\n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\}\n\nSubscribe:\ print\ program\ from\ editor\ /editor/\ \{\n\ \ \ \ set\ options\ \[editorToPrintOptions\ \$editor\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n\}\n\n#\ Print\ preview:\nWhen\ the\ codeToPostScript\ is\ /codeToPostScript/\ &\\\n\ \ \ \ \ /someone/\ wishes\ editor\ /editor/\ has\ a\ print\ preview\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ \{\n\n\ \ \ \ set\ preview\ \[list\ \$editor\ preview\]\n\ \ \ \ Wish\ \$preview\ has\ a\ canvas\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ previewGeom\ \[list\ width\ \[/\ \[lindex\ \$fmt(pageSize)\ 0\]\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[/\ \[lindex\ \$fmt(pageSize)\ 1\]\ \$mToPt\]\]\n\ \ \ \ Claim\ \$preview\ has\ resolved\ geometry\ \$previewGeom\n\ \ \ \ When\ the\ quad\ library\ is\ /quadLib/\ &\ \$editor\ has\ quad\ /q/\ \{\n\ \ \ \ \ \ \ \ Claim\ \$preview\ has\ quad\ \[\$quadLib\ alignGeometry\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$quadLib\ move\ \$q\ right\ 100%\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$previewGeom\]\n\ \ \ \ \}\n\ \ \ \ Wish\ \$preview\ is\ outlined\ white\n\n\ \ \ \ fn\ codeToPostScript\n\ \ \ \ When\ editor\ buffer\ for\ \$program\ is\ /code/\ \{\n\ \ \ \ \ \ \ \ set\ ps\ \[codeToPostScript\ 48700\ \$code\ \[editorToPrintOptions\ \$editor\]\]\n\n\ \ \ \ \ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ \ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ \ \ \ \ set\ result\ \[exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r300\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\]\n\ \ \ \ \ \ \ \ puts\ stderr\ \"gs\ to\ render\ preview:\ \$result\"\n\ \ \ \ \ \ \ \ Wish\ \$preview\ displays\ image\ \$pngFile\ with\ width\ \$previewGeom(width)\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/editor/editor-utils.folk has program code {Claim the editor utils l (
[ m192:0 (s293:0) ]
)<unknown> claims builtin-programs/editor/editor-utils.folk has program code {Claim the editor utils library is [library create editorUtilsLib {
proc applyTextViewport {originalText x y width height} {
set lines [split $originalText \n]
set lines [lrange $lines $y [expr {($height - 1) + $y}]]
set lines [lmap line $lines {
set line [string range $line $x [expr {($width - 1) + $x}]]
}]
return [join $lines \n]
}
proc cursorToXy {code cursor} {
set codeBeforeCursor [string range $code 0 [- $cursor 1]]
set linesBeforeCursor [split $codeBeforeCursor "\n"]
set lineCountBeforeCursor [llength $linesBeforeCursor]
set cursorX [string length [lindex $linesBeforeCursor end]]
set cursorY [max [- $lineCountBeforeCursor 1] 0]
return [list $cursorX $cursorY]
}
proc xyToCursor {code cursorX cursorY} {
if { $cursorX < 0 } { set cursorX 0 }
if { $cursorY < 0 } { set cursorY 0 }
set lines [split $code "\n"]
set maxCursorY [max 0 [- [llength $lines] 1]]
set cursorY [min $cursorY $maxCursorY]
set relevantLines [lrange $lines 0 [- $cursorY 1]]
set relevantLineLen [string length [lindex $lines $cursorY]]
set joined [join $relevantLines "\n"]
# make sure cursorX < line length
set cursorX [min $cursorX $relevantLineLen]
set cursor [+ [string length $joined] $cursorX]
# don't forget to add the length of \n at the beginning
if {$cursorY > 0} { incr cursor }
return $cursor
}
proc insertText {code cursor newText} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code $cursor end]
set joined [join [list $before $newText $after] ""]
incr cursor
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $joined $cursor $maxCursorX]
}
proc deleteText {code cursor count} {
set before [string range $code 0 [- $cursor 1]]
set after [string range $code [+ $cursor $count] end]
set joined [join [list $before $after] ""]
return $joined
}
proc deleteToBeginning {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
set newLine [string range $line $x end]
lset lines $y $newLine
return [join $lines "\n"]
}
proc getLine {code cursor} {
lassign [cursorToXy $code $cursor] x y
set lines [split $code "\n"]
set line [lindex $lines $y]
}
proc getLineLength {code cursor} {
set line [getLine $code $cursor]
set ll [string length $line]
return $ll
}
# returns {newCursor newMaxCursorX}
proc handleNavigation {key code cursor maxCursorX} {
switch $key {
Left {
set cursor [- $cursor 1]
set cursor [max $cursor 0]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Right {
set cursor [+ $cursor 1]
set codeLength [string length $code]
set cursor [min $cursor $codeLength]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
}
Up {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [- $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Down {
lassign [cursorToXy $code $cursor] cursorX cursorY
set cursorX $maxCursorX
set cursorY [+ $cursorY 1]
set cursor [xyToCursor $code $cursorX $cursorY]
}
Control_a {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX 0
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
Control_e {
lassign [cursorToXy $code $cursor] cursorX cursorY
set newX [getLineLength $code $cursor]
set maxCursorX $newX
set cursor [xyToCursor $code $newX $cursorY]
}
}
return [list $cursor $maxCursorX]
}
# returns {newCode newCursor newMaxCursorX}
proc handleRemovalAndReturn {key code cursor maxCursorX} {
switch $key {
Delete {
if { $cursor != 0 } {
set cursor [- $cursor 1]
set code [deleteText $code $cursor 1]
set maxCursorX [lindex [cursorToXy $code $cursor] 0]
}
}
Remove {
set code [deleteText $code $cursor 1]
}
Control_u {
# delete from cursor back to 0 and move cursor to 0
lassign [cursorToXy $code $cursor] cursorX cursorY
set code [deleteToBeginning $code $cursor]
set newX 0
set cursor [xyToCursor $code $newX $cursorY]
}
Return {
# figure out how many spaces there are before the current line
regexp {^(\s*)} [getLine $code $cursor] -> spacing
set spacingLen [string length $spacing]
lassign [insertText $code $cursor "\n$spacing"] code
set maxCursorX $spacingLen
set cursor [+ $cursor [+ 1 $spacingLen]]
}
}
return [list $code $cursor $maxCursorX]
}
proc getSelectedText {code selAnchor cursor} {
set start [min $selAnchor $cursor]
set end [max $selAnchor $cursor]
return [string range $code $start [- $end 1]]
}
proc replaceRange {code rangeStart rangeEnd newText} {
if {$rangeStart > 0} {
set before [string range $code 0 [- $rangeStart 1]]
} else {
set before ""
}
set after [string range $code $rangeEnd end]
set code "${before}${newText}${after}"
set cursor [+ $rangeStart [string length $newText]]
lassign [cursorToXy $code $cursor] cursorX cursorY
set maxCursorX $cursorX
return [list $code $cursor $maxCursorX]
}
proc lineNumberView {ystart linecount} {
set yend [expr {$ystart + $linecount}]
set numbers [list]
for {set i [expr {$ystart + 1}]} {$i <= $yend} {incr i} {
lappend numbers $i
}
join $numbers "\n"
}
# For rendering:
proc getAdvance {em} {
# From NeomatrixCode.csv
return $(0.5859375 * $em)
}
proc widthAndHeight {resolvedGeom} {
set tagSize [dict get $resolvedGeom tagSize]
set left [dict get $resolvedGeom left]
set right [dict get $resolvedGeom right]
set top [dict get $resolvedGeom top]
set bottom [dict get $resolvedGeom bottom]
set width $($left + $tagSize + $right)
set height $($top + $tagSize + $bottom)
return [list $width $height]
}
# given program and the editor options, figure out how many characters can
# fit in this editor
proc editorSizeInCharacters {margin resolvedGeom options} {
set textScale [dict get $options scale]
set advance [getAdvance $textScale]
lassign [widthAndHeight $resolvedGeom] width height
set width $($width - [lindex $margin 3] - $advance*2.5 - [lindex $margin 1])
set height $($height - [lindex $margin 0] - [lindex $margin 2])
set widthInCharacters $(int($width / $advance))
set heightInCharacters $(int($height / $textScale))
return [list $widthInCharacters $heightInCharacters]
}
}]
}
<unknown> claims builtin-programs/editor/draw-editor.folk has program code When\ the\ editor\ utils\ (
[ m194:0 (s296:0) ]
)<unknown> claims builtin-programs/editor/draw-editor.folk has program code When\ the\ editor\ utils\ library\ is\ /utils/\ \{\n\n#\ Draw\ text\ and\ cursor\nWhen\ /editor/\ is\ an\ editor\ with\ /...anything/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ margin\ /margin/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ position\ /vpPos/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ viewport\ size\ /vpSize/\ &\\\n\ \ \ \ \ editor\ /editor/\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ editor\ /editor/\ on\ program\ /program/\ has\ font\ options\ with\ /...fontOptions/\ \{\n\ \ \ \ lassign\ \$vpPos\ vpX\ vpY\n\ \ \ \ lassign\ \$vpSize\ vpWidth\ vpHeight\n\n\ \ \ \ #\ Editor\ backdrop.\n\ \ \ \ When\ \$editor\ has\ canvas\ /editorCanvas/\ with\ /...wiOpts/\ \{\n\ \ \ \ \ \ \ \ set\ bgColor\ \[list\ 0\ 0\ 0\ 0.8\]\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ -1\]\ \[list\ 1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"fillTriangle\"\ onto\ canvas\ \$editorCanvas\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ arguments\ \[list\ \{\{1\ 0\ 0\}\ \{0\ 1\ 0\}\ \{0\ 0\ 1\}\}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ -1\ -1\]\ \[list\ 1\ 1\]\ \[list\ -1\ 1\]\ \$bgColor\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ layer\ -2\n\ \ \ \ \}\n\n\ \ \ \ #\ Editor\ gold\ dashed\ outline.\n\ \ \ \ When\ \$editor\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ \ \ \ \ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ dashed\ line\ onto\ \$editor\ with\ points\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$geom(width)\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$geom(height)\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ color\ gold\ width\ 0.005\ dashlength\ 0.008\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ dashoffset\ \[expr\ \{fmod(\$t,\ 1.6)\ *\ 0.01\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ textScale\ \[dict\ get\ \$fontOptions\ scale\]\n\ \ \ \ set\ advance\ \[\$utils\ getAdvance\ \$textScale\]\n\n\ \ \ \ When\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /code/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ /cursor/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ cursor\ position\ /cursorPos/\ &\\\n\ \ \ \ \ \ \ \ \ editor\ \$editor\ has\ selection\ anchor\ /selAnchor/\ \{\n\ \ \ \ \ \ \ \ set\ lineCount\ \[min\ \[-\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\ \$vpY\]\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ lineNumbers\ \[\$utils\ lineNumberView\ \$vpY\ \$lineCount\]\n\n\ \ \ \ \ \ \ \ set\ marginLeft\ \[lindex\ \$margin\ 3\]\n\ \ \ \ \ \ \ \ set\ lineNumbersRight\ \$(\$marginLeft\ +\ \$advance*1.5)\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \[list\ \$lineNumbersRight\ \[lindex\ \$margin\ 0\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ text\ \$lineNumbers\ color\ gold\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topright\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ set\ text\ \[\$utils\ applyTextViewport\ \$code\ \$vpX\ \$vpY\ \$vpWidth\ \$vpHeight\]\n\ \ \ \ \ \ \ \ set\ pos\ \[list\ \[+\ \$lineNumbersRight\ \$advance\]\ \[lindex\ \$margin\ 0\]\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ text\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ position\ \$pos\ text\ \$text\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ scale\ \$textScale\ anchor\ topleft\ font\ NeomatrixCode\n\n\ \ \ \ \ \ \ \ #\ Draw\ selection\ highlight\n\ \ \ \ \ \ \ \ if\ \{\$selAnchor\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawStart\ \[min\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rawEnd\ \[max\ \$selAnchor\ \$cursor\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawStart\]\ selStartX\ selStartY\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$utils\ cursorToXy\ \$code\ \$rawEnd\]\ selEndX\ selEndY\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lines\ \[split\ \$code\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ ly\ \$selStartY\}\ \{\$ly\ <=\ \$selEndY\}\ \{incr\ ly\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ <\ \$vpY\ ||\ \$ly\ >=\ \$vpY\ +\ \$vpHeight\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lineLen\ \[string\ length\ \[lindex\ \$lines\ \$ly\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Absolute\ column\ range\ for\ selection\ on\ this\ line\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selStartY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \$selStartX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$ly\ ==\ \$selEndY\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$selEndX\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \$lineLen\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Clip\ to\ viewport\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absStart\ \[max\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ absEnd\ \[min\ \$absEnd\ \[+\ \$vpX\ \$vpWidth\]\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$absStart\ >=\ \$absEnd\}\ continue\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Convert\ to\ display\ coordinates\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispStart\ \[-\ \$absStart\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispEnd\ \[-\ \$absEnd\ \$vpX\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ dispRow\ \[-\ \$ly\ \$vpY\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x0\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispStart\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x1\ \$(\[lindex\ \$pos\ 0\]\ +\ \$dispEnd\ *\ \$advance)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y0\ \$(\[lindex\ \$pos\ 1\]\ +\ \$dispRow\ *\ \$textScale)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ y1\ \$(\$y0\ +\ \$textScale)\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ quad\ onto\ \$editor\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p0\ \[list\ \$x0\ \$y0\]\ p1\ \[list\ \$x1\ \$y0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p2\ \[list\ \$x1\ \$y1\]\ p3\ \[list\ \$x0\ \$y1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ color\ \{0.2\ 0.4\ 0.8\ 0.7\}\ layer\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ p1\ \[vec2\ add\ \$cursorPos\ \$pos\]\n\ \ \ \ \ \ \ \ set\ p2\ \[vec2\ add\ \$p1\ \[list\ 0\ \[*\ \$textScale\ 1.2\]\]\]\n\ \ \ \ \ \ \ \ set\ s\ \[/\ \$textScale\ 6\]\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ circle\ onto\ \$editor\ with\ center\ \$p1\ radius\ \$s\ thickness\ 0\ color\ green\ filled\ true\n\ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$editor\ with\ points\ \[list\ \$p1\ \$p2\]\ width\ \$s\ color\ green\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/decorations/outline.folk has program code When\ /someone/\ wishes\ (
[ m196:0 (s299:0) ]
)<unknown> claims builtin-programs/decorations/outline.folk has program code When\ /someone/\ wishes\ /thing/\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ /thing/\ has\ resolved\ geometry\ /geom/\ \{\n\ \ \ \ dict\ with\ geom\ \{\n\ \ \ \ \ \ \ \ set\ points\ \[list\ \[list\ 0\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ 0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$width\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ \$height\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0\ 0\]\]\n\ \ \ \ \}\n\n\ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$thing\ with\ \\\n\ \ \ \ \ \ \ \ points\ \$points\ width\ 0.01\ color\ \$color\n\}\n
<unknown> claims builtin-programs/decorations/label.folk has program code {When /thing/ has resolved (
[ m198:0 (s301:0) ]
)<unknown> claims builtin-programs/decorations/label.folk has program code {When /thing/ has resolved geometry /geom/ {
When the collected results for [list /someone/ wishes $thing is labelled /text/ with /...options/] are /results/ {
set text [join [lmap result $results {dict get $result text}] "\n"]
if {$text eq ""} { return }
# Split text into lines and find the longest line.
set lines [split $text "\n"]
set maxLength 0
foreach line $lines {
set lineLength [string length $line]
if {$lineLength > $maxLength} {
set maxLength $lineLength
}
}
# Set default scale based on longest line length.
# Scale inversely with length to keep text readable.
set defaultScale [::math::min 0.02 [/ 0.45 $maxLength]]
set x [/ $geom(width) 2.0]
try {
set y $($geom(top) + $geom(tagSize) + $geom(bottom)/2.0)
} on error e {
set y [/ $geom(height) 2.0]
}
set options [dict create x $x y $y scale $defaultScale]
# FIXME: support per-label options; right now, this just
# applies an arbitrary label's options to all of them
# together.
set options [dict merge $options [dict get $result options]]
dict set options text $text
Wish to draw text onto $thing with {*}$options
}
}
When /someone/ wishes /thing/ is labelled /text/ {
Wish $thing is labelled $text with font "PTSans-Regular"
}
}
<unknown> claims builtin-programs/camera/rpi.folk has program code #\ camera/rpi.folk\ --\n#\n#\ \ \ (
[ m201:0 (s305:0) ]
)<unknown> claims builtin-programs/camera/rpi.folk has program code #\ camera/rpi.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ Pi\ webcams\ (libcamera).\n\nif\ \{\$::tcl_platform(os)\ eq\ \"darwin\"\}\ \{\n\ \ \ \ error\ \"Raspberry\ Pi\ camera\ driver\ only\ runs\ on\ Linux.\"\n\}\n\nset\ makeCamera\ \{\n\ \ \ \ set\ cpp\ \[C++\]\n\ \ \ \ \$cpp\ extend\ \$imageLib\n\ \ \ \ \$cpp\ include\ <iostream>\n\ \ \ \ \$cpp\ include\ <iomanip>\n\ \ \ \ \$cpp\ include\ <mutex>\n\ \ \ \ \$cpp\ include\ <condition_variable>\n\ \ \ \ \$cpp\ include\ <queue>\n\ \ \ \ \$cpp\ include\ <sys/mman.h>\n\n\ \ \ \ \$cpp\ include\ <libcamera/libcamera.h>\n\ \ \ \ #\ osnr:\ HACK:\ just\ throwing\ any\ possible\ path\ in.\n\ \ \ \ \$cpp\ cflags\ -I/usr/local/include/libcamera\ -I/usr/include/libcamera\n\ \ \ \ \$cpp\ endcflags\ -lcamera\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ using\ namespace\ libcamera\;\n\n\ \ \ \ \ \ \ \ std::unique_ptr<CameraManager>\ cm\;\n\ \ \ \ \ \ \ \ std::shared_ptr<Camera>\ camera\;\n\tstd::unique_ptr<CameraConfiguration>\ config\;\n\tFrameBufferAllocator\ *allocator\;\n\n\ \ \ \ \ \ \ \ //\ This\ vector\ always\ owns\ all\ the\ request\ objects.\n\tstd::vector<std::unique_ptr<Request>>\ requests\;\n\n\ \ \ \ \ \ \ \ std::mutex\ completedRequestsMutex\;\n\ \ \ \ \ \ \ \ std::queue<Request\ *>\ completedRequests\;\n\ \ \ \ \ \ \ \ std::condition_variable\ completedRequestsCv\;\n\n\ \ \ \ \ \ \ \ uint32_t\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ frameHeight\;\n\ \ \ \ \ \ \ \ uint32_t\ frameBytesPerRow\;\n\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ cameraOpen\ \{char*\ id\ int\ width\ int\ height\}\ void\ \{\n\ \ \ \ \ \ \ \ cm\ =\ std::make_unique<CameraManager>()\;\n\ \ \ \ \ \ \ \ cm->start()\;\n\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ cameras:\"\ <<\ std::endl\;\n\tfor\ (auto\ const\ &camera\ :\ cm->cameras())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"\ -\ \"\ <<\ camera->id()\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ camera\ =\ cm->get(id)\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(camera\ !=\ nullptr)\;\n\ \ \ \ \ \ \ \ camera->acquire()\;\n\n\ \ \ \ \ \ \ \ config\ =\ camera->generateConfiguration(\{\ StreamRole::Viewfinder\ \})\;\n\ \ \ \ \ \ \ \ StreamConfiguration\ &streamConfig\ =\ config->at(0)\;\n\ \ \ \ \ \ \ \ streamConfig.size\ =\ Size(width,\ height)\;\n\ \ \ \ \ \ \ \ streamConfig.pixelFormat\ =\ PixelFormat::fromString(\"YUV420\")\;\n\n\ \ \ \ \ \ \ \ config->validate()\;\n\ \ \ \ \ \ \ \ frameWidth\ =\ streamConfig.size.width\;\n\ \ \ \ \ \ \ \ frameHeight\ =\ streamConfig.size.height\;\n\ \ \ \ \ \ \ \ frameBytesPerRow\ =\ streamConfig.stride\;\n\ \ \ \ \ \ \ \ std::cout\ <<\ \"frameWidth:\ \"\ <<\ frameWidth\ <<\ \"\ frameHeight:\ \"\ <<\ frameHeight\ <<\ std::endl\;\n\n\tcamera->configure(config.get())\;\n\n\ \ \ \ \ \ \ \ allocator\ =\ new\ FrameBufferAllocator(camera)\;\n\tfor\ (StreamConfiguration\ &cfg\ :\ *config)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ ret\ =\ allocator->allocate(cfg.stream())\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"Can't\ allocate\ buffers\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ size_t\ allocated\ =\ allocator->buffers(cfg.stream()).size()\;\n\ \ \ \ \ \ \ \ \ \ \ \ std::cout\ <<\ \"camera/rpi:\ Allocated\ \"\ <<\ allocated\ <<\ \"\ buffers\ for\ stream\"\ <<\ std::endl\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (PixelFormat\ &format\ :\ cfg.formats().pixelformats())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ std::cout\ <<\ \"camera/rpi:\ Stream\ supports\ format\ \"\ <<\ format\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ for\ (Size\ &size\ :\ cfg.formats().sizes(format))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \ \ \ \ std::cout\ <<\ \"\ \ ->\ supports\ size\ \"\ <<\ size\ <<\ std::endl\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ //\ \}\n\t\}\n\n\ \ \ \ \ \ \ \ Stream\ *stream\ =\ streamConfig.stream()\;\n\ \ \ \ \ \ \ \ assert(streamConfig.pixelFormat.toString()\ ==\ \"YUV420\")\;\n\n\ \ \ \ \ \ \ \ const\ std::vector<std::unique_ptr<FrameBuffer>>\ &buffers\ =\ allocator->buffers(stream)\;\n\tfor\ (unsigned\ int\ i\ =\ 0\;\ i\ <\ buffers.size()\;\ ++i)\ \{\n\t\tstd::unique_ptr<Request>\ request\ =\ camera->createRequest()\;\n\t\tif\ (!request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ create\ request\")\;\n\t\t\}\n\n\t\tconst\ std::unique_ptr<FrameBuffer>\ &buffer\ =\ buffers\[i\]\;\n\t\tint\ ret\ =\ request->addBuffer(stream,\ buffer.get())\;\n\t\tif\ (ret\ <\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ Can't\ set\ buffer\ for\ request\")\;\n\t\t\}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ControlList\ &controls\ =\ request->controls()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AeEnable,\ false)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::ExposureTime,\ 35000)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::AfMode,\ controls::AfModeManual)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ Focus\ 30cm\ away\ (0.3m\ ->\ 1/0.3\ =\ 3.3).\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ controls.set(controls::LensPosition,\ 1.6)\;\n\n\t\trequests.push_back(std::move(request))\;\n\t\}\n\n\tcamera->requestCompleted.connect(requestComplete)\;\n\n\ \ \ \ \ \ \ \ camera->start()\;\n\tfor\ (std::unique_ptr<Request>\ &request\ :\ requests)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(request.get())\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ code\ \{\n\ \ \ \ \ \ \ \ static\ void\ requestComplete(Request\ *request)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (request->status()\ ==\ Request::RequestCancelled)\ \{\n\t\treturn\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.lock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.push(request)\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsMutex.unlock()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequestsCv.notify_one()\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ static\ void\ processRequestAndCopyFrame(Request\ *request,\ Image\ im)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ Request::BufferMap\ &buffers\ =\ request->buffers()\;\n\ \ \ \ \ \ \ \ \ \ \ \ assert(buffers.size()\ ==\ 1)\;\n\ \ \ \ \ \ \ \ \ \ \ \ for\ (auto\ bufferPair\ :\ buffers)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ (Unused)\ Stream\ *stream\ =\ bufferPair.first\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FrameBuffer\ *buffer\ =\ bufferPair.second\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ FrameMetadata\ &metadata\ =\ buffer->metadata()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(metadata.planes().size()\ ==\ 3)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ assert(buffer->planes().size()\ ==\ 3)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto\ &plane\ =\ buffer->planes()\[0\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ int\ fd\ =\ plane.fd.get()\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *addr\ =\ mmap64(NULL,\ plane.length,\ PROT_READ,\ MAP_PRIVATE,\ fd,\ 0)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (addr\ ==\ MAP_FAILED)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/rpi:\ MAP_FAILED\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ void\ *planeData\ =\ (uint8_t\ *)addr\ +\ plane.offset\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ memcpy(im.data,\ planeData,\ frameHeight\ *\ frameBytesPerRow)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ munmap(addr,\ plane.length)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ newImage\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ uint32_t\ width\ =\ frameWidth\;\n\ \ \ \ \ \ \ \ uint32_t\ height\ =\ frameHeight\;\n\ \ \ \ \ \ \ \ int\ components\ =\ 1\;\n\ \ \ \ \ \ \ \ uint8_t\ *data\ =\ (uint8_t\ *)\ malloc(width*components*height)\;\n\ \ \ \ \ \ \ \ return\ (Image)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ .width\ =\ width,\n\ \ \ \ \ \ \ \ \ \ \ \ .height\ =\ height,\n\ \ \ \ \ \ \ \ \ \ \ \ .components\ =\ components,\n\ \ \ \ \ \ \ \ \ \ \ \ .bytesPerRow\ =\ width*components,\n\ \ \ \ \ \ \ \ \ \ \ \ .data\ =\ data\n\ \ \ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\ \ \ \ \$cpp\ proc\ freeImage\ \{Image\ image\}\ void\ \{\n\ \ \ \ \ \ \ \ free(image.data)\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ proc\ grayFrame\ \{\}\ Image\ \{\n\ \ \ \ \ \ \ \ Request\ *latestRequest\ =\ nullptr\;\n\n\ \ \ \ \ \ \ \ //\ We\ want\ to\ drain\ the\ queue\ of\ completed\ requests.\n\ \ \ \ \ \ \ \ std::unique_lock\ lk(completedRequestsMutex)\;\n\ \ \ \ \ \ \ \ completedRequestsCv.wait(lk,\ \[\]\{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ !completedRequests.empty()\;\n\ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ while\ (!completedRequests.empty())\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (latestRequest\ !=\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ We're\ skipping\ this\ request,\ because\ we\ have\ a\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ //\ newer\ one\ in\ the\ queue.\ Requeue\ it.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ latestRequest\ =\ completedRequests.front()\;\n\ \ \ \ \ \ \ \ \ \ \ \ completedRequests.pop()\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lk.unlock()\;\n\n\ \ \ \ \ \ \ \ if\ (latestRequest\ ==\ nullptr)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ FOLK_ERROR(\"No\ new\ frame\ yet\")\;\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Image\ im\ =\ newImage()\;\n\ \ \ \ \ \ \ \ processRequestAndCopyFrame(latestRequest,\ im)\;\n\n\ \ \ \ \ \ \ \ /*\ Re-queue\ the\ Request\ to\ the\ camera.\ */\n\ \ \ \ \ \ \ \ latestRequest->reuse(Request::ReuseBuffers)\;\n\ \ \ \ \ \ \ \ camera->queueRequest(latestRequest)\;\n\n\ \ \ \ \ \ \ \ return\ im\;\n\ \ \ \ \}\n\n\ \ \ \ \$cpp\ compile\n\}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /cameraPath/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/base*\"\ \$cameraPath\]\}\ \{\ return\ \}\n\n\ \ \ \ puts\ \"camera/rpi:\ Running.\"\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\n\ \ \ \ set\ camLib\ \[eval\ \$makeCamera\]\n\ \ \ \ \$camLib\ cameraOpen\ \$cameraPath\ \$width\ \$height\n\n\ \ \ \ #\ TODO:\ report\ actual\ width\ and\ height\ from\ libcamera\n\ \ \ \ Claim\ camera\ \$cameraPath\ has\ width\ \$width\ height\ \$height\n\n\ \ \ \ puts\ \"camera/rpi:\ \$cameraPath\ (\$options)\ booted\ at\ \[clock\ milliseconds\]\"\n\n\ \ \ \ set\ oldFrames\ \[list\]\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frame\ \[\$camLib\ grayFrame\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"err:\ \$e\"\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\[clock\ milliseconds\]\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/rpi:\ \$timestamp\"\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frame\ at\ timestamp\ \$timestamp\n\n\ \ \ \ \ \ \ \ lappend\ oldFrames\ \$frame\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$oldFrames\]\ >=\ 10\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ oldFrames\ \[lassign\ \$oldFrames\ oldestFrame\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ freeImage\ \$oldestFrame\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \}\n\}\n
<unknown> claims builtin-programs/camera/enumerate.folk has program code {if {$::tcl_platform(os) ne (
[ m202:0 (s307:0) ]
)<unknown> claims builtin-programs/camera/enumerate.folk has program code {if {$::tcl_platform(os) ne "linux"} { return }
set cc [C]
$cc include <fcntl.h>
$cc include <unistd.h>
$cc include <sys/ioctl.h>
$cc include <linux/videodev2.h>
$cc proc getInfoForCamera {char* camera} Jim_Obj* {
int fd = open(camera, O_RDWR);
FOLK_ENSURE(fd >= 0);
Jim_Obj *infoObj = Jim_NewDictObj(interp, NULL, 0);
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0) {
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "card", -1),
Jim_NewStringObj(interp, (const char *)cap.card, -1));
}
Jim_Obj *formatsList = Jim_NewListObj(interp, NULL, 0);
// Enumerate pixel formats
struct v4l2_fmtdesc fmt_desc = {0};
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
char fourcc_str[5];
fourcc_str[0] = fmt_desc.pixelformat & 0xFF;
fourcc_str[1] = (fmt_desc.pixelformat >> 8) & 0xFF;
fourcc_str[2] = (fmt_desc.pixelformat >> 16) & 0xFF;
fourcc_str[3] = (fmt_desc.pixelformat >> 24) & 0xFF;
fourcc_str[4] = '\0';
Jim_Obj *resolutionsList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmsizeenum frm_size = {0};
frm_size.pixel_format = fmt_desc.pixelformat;
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frm_size) == 0) {
if (frm_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Jim_Obj *frameratesList = Jim_NewListObj(interp, NULL, 0);
struct v4l2_frmivalenum frm_interval = {0};
frm_interval.pixel_format = fmt_desc.pixelformat;
frm_interval.width = frm_size.discrete.width;
frm_interval.height = frm_size.discrete.height;
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval) == 0) {
if (frm_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
double fps = (double)frm_interval.discrete.denominator /
frm_interval.discrete.numerator;
Jim_ListAppendElement(interp, frameratesList, Jim_NewDoubleObj(interp, fps));
} else if (frm_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
double min_fps = (double)frm_interval.stepwise.max.denominator /
frm_interval.stepwise.max.numerator;
double max_fps = (double)frm_interval.stepwise.min.denominator /
frm_interval.stepwise.min.numerator;
Jim_Obj *rangeDict = Jim_ObjPrintf("min %f max %f", min_fps, max_fps);
Jim_ListAppendElement(interp, frameratesList, rangeDict);
}
frm_interval.index++;
}
int frameratesLen;
const char *frameratesStr = Jim_GetString(frameratesList, &frameratesLen);
Jim_Obj *resDict = Jim_ObjPrintf("width %u height %u framerates {%s}",
frm_size.discrete.width,
frm_size.discrete.height,
frameratesStr);
Jim_ListAppendElement(interp, resolutionsList, resDict);
}
frm_size.index++;
}
int resolutionsLen;
const char *resolutionsStr = Jim_GetString(resolutionsList, &resolutionsLen);
Jim_Obj *formatDict = Jim_ObjPrintf("fourcc {%s} description {%s} resolutions {%s}",
fourcc_str,
(char*)fmt_desc.description,
resolutionsStr);
Jim_ListAppendElement(interp, formatsList, formatDict);
fmt_desc.index++;
}
Jim_DictAddElement(interp, infoObj,
Jim_NewStringObj(interp, "formats", -1),
formatsList);
close(fd);
return infoObj;
}
set formatsLib [$cc compile]
set camerasByCanonicalName [dict create]
set cameras [glob -nocomplain "/dev/v4l/by-path/*"]
# sort first so the order (and therefore which dedupe wins) is
# consistent across boots.
set cameras [lsort $cameras]
foreach camera $cameras {
# I would prefer to use by-id, but not all cameras show up in
# by-id (webcam on my Dell laptop does not, for instance).
try {
set canonicalName [file readlink $camera]
} on error e {
set canonicalName $camera
}
if {[dict exists $camerasByCanonicalName $canonicalName]} {
# Skip cameras that we already have by another name, so there
# aren't dupes in the enumeration (in particular, by-path
# often has both -usb- and -usbv2- copies of a camera).
continue
}
dict set camerasByCanonicalName $canonicalName $camera
set info [$formatsLib getInfoForCamera $camera]
Claim $::thisNode has camera $camera with {*}$info
}
}
<unknown> claims builtin-programs/camera/usb.folk has program code #\ camera/usb.folk\ --\n#\n#\ \ \ (
[ m205:0 (s312:0) ]
)<unknown> claims builtin-programs/camera/usb.folk has program code #\ camera/usb.folk\ --\n#\n#\ \ \ \ \ Hardware\ interface\ with\ USB\ webcams\ on\ Linux\ (v4l2).\n\nif\ \{\$::tcl_platform(os)\ ne\ \"linux\"\}\ \{\ return\ \}\n\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ jpeg\ library\ is\ /jpegLib/\ \{\n\nset\ camc\ \[C\]\n\$camc\ extend\ \$imageLib\n\$camc\ include\ <string.h>\n\$camc\ include\ <math.h>\n\n\$camc\ include\ <errno.h>\n\$camc\ include\ <fcntl.h>\n\$camc\ include\ <sys/ioctl.h>\n\$camc\ include\ <sys/mman.h>\n\$camc\ include\ <asm/types.h>\n\$camc\ include\ <linux/videodev2.h>\n\$camc\ include\ <unistd.h>\n\n\$camc\ include\ <stdint.h>\n\$camc\ include\ <stdlib.h>\n\n\$camc\ struct\ CameraBuffer\ \{\n\ \ \ \ uint8_t*\ start\;\n\ \ \ \ size_t\ length\;\n\}\n\$camc\ struct\ Camera\ \{\n\ \ \ \ int\ fd\;\n\ \ \ \ uint32_t\ width\;\n\ \ \ \ uint32_t\ height\;\n\ \ \ \ size_t\ buffer_count\;\n\ \ \ \ CameraBuffer*\ buffers\;\n\ \ \ \ CameraBuffer\ head\;\n\}\n\n\$camc\ code\ \{\n\ \ \ \ void\ quit(const\ char*\ msg)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"camera/usb:\ Quitting:\ \[%s\]\ %d:\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ msg,\ errno,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ int\ xioctl(int\ fd,\ int\ request,\ void*\ arg)\ \{\n\ \ \ \ \ \ \ \ for\ (int\ i\ =\ 0\;\ i\ <\ 100\;\ i++)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ int\ r\ =\ ioctl(fd,\ request,\ arg)\;\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (r\ !=\ -1\ ||\ errno\ !=\ EINTR)\ return\ r\;\n\ \ \ \ \ \ \ \ \ \ \ \ printf(\"camera/usb:\ Retrying:\ \[%x\]\[%d\]\ %s\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ request,\ i,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ -1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraOpen\ \{char*\ device\ int\ width\ int\ height\}\ Camera*\ \{\n\ \ \ \ printf(\"camera/usb:\ Loading\ '%s'\\n\",\ device)\;\n\ \ \ \ //\ O_CLOEXEC\ is\ necessary\ so\ long-running\ child\ processes\ (like\n\ \ \ \ //\ fswatch)\ don't\ keep\ the\ camera\ open\ past\ the\ death\ of\ folk\n\ \ \ \ //\ itself,\ which\ causes\ EBUSY\ for\ the\ next\ Folk\ process.\n\ \ \ \ int\ fd\ =\ open(device,\ O_RDWR\ |\ O_NONBLOCK\ |\ O_CLOEXEC,\ 0)\;\n\ \ \ \ if\ (fd\ ==\ -1)\ quit(\"open\")\;\n\ \ \ \ Camera*\ camera\ =\ malloc(sizeof(Camera))\;\n\ \ \ \ camera->fd\ =\ fd\;\n\ \ \ \ camera->width\ =\ width\;\n\ \ \ \ camera->height\ =\ height\;\n\ \ \ \ camera->buffer_count\ =\ 0\;\n\ \ \ \ camera->buffers\ =\ NULL\;\n\ \ \ \ camera->head.length\ =\ 0\;\n\ \ \ \ camera->head.start\ =\ NULL\;\n\ \ \ \ return\ camera\;\n\}\n\$camc\ proc\ cameraClose\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMOFF,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ //\ if\ ENODEV,\ we're\ already\ done\;\ just\ return\ to\ caller.\n\ \ \ \ \ \ \ \ if\ (errno\ ==\ ENODEV)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"cameraClose\ (%p):\ ENODEV,\ returning.\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ close(camera->fd)\;\n\ \ \ \ \ \ \ \ \ \ \ \ free(camera)\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ //\ stop,\ something\ weird\ happened.\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMOFF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ //\ A\ count\ value\ of\ zero\ frees\ all\ buffers,\ after\ aborting\ or\n\ \ \ \ //\ finishing\ any\ DMA\ in\ progress,\ an\ implicit\ VIDIOC_STREAMOFF.\n\ \ \ \ req.count\ =\ 0\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ \}\n\ \ \ \ if\ (close(camera->fd)\ !=\ 0)\ \{\n\ \ \ \ \ \ \ \ quit(\"close\")\;\n\ \ \ \ \}\n\ \ \ \ free(camera)\;\n\}\n\n\$camc\ proc\ cameraInit\ \{Camera*\ camera\ uint32_t\ requested_buffer_count\}\ void\ \{\n\ \ \ \ struct\ v4l2_capability\ cap\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYCAP,\ &cap)\ ==\ -1)\ quit(\"VIDIOC_QUERYCAP\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_VIDEO_CAPTURE))\ quit(\"no\ capture\")\;\n\ \ \ \ if\ (!(cap.capabilities\ &\ V4L2_CAP_STREAMING))\ quit(\"no\ streaming\")\;\n\n\ \ \ \ struct\ v4l2_format\ format\ =\ \{0\}\;\n\ \ \ \ format.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ format.fmt.pix.width\ =\ camera->width\;\n\ \ \ \ format.fmt.pix.height\ =\ camera->height\;\n\ \ \ \ format.fmt.pix.pixelformat\ =\ V4L2_PIX_FMT_MJPEG\;\n\ \ \ \ format.fmt.pix.field\ =\ V4L2_FIELD_NONE\;\n\ \ \ \ int\ ret\;\n\ \ \ \ do\ \{\n\ \ \ \ \ \ \ \ ret\ =\ xioctl(camera->fd,\ VIDIOC_S_FMT,\ &format)\;\n\ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ VIDIOC_S_FMT:\ ret\ =\ %d\ (%d)\ (%s)\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ret,\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ usleep(100000)\;\n\ \ \ \ \}\ while\ (ret\ ==\ -1\ &&\ errno\ ==\ EBUSY)\;\n\ \ \ \ if\ (ret\ ==\ -1)\ quit(\"VIDIOC_S_FMT\")\;\n\n\ \ \ \ struct\ v4l2_requestbuffers\ req\ =\ \{0\}\;\n\ \ \ \ req.count\ =\ requested_buffer_count\;\n\ \ \ \ req.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ req.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_REQBUFS,\ &req)\ ==\ -1)\ quit(\"VIDIOC_REQBUFS\")\;\n\ \ \ \ camera->buffer_count\ =\ req.count\;\n\ \ \ \ camera->buffers\ =\ calloc(req.count,\ sizeof\ (CameraBuffer))\;\n\n\ \ \ \ printf(\"LATENCY:\ Camera\ buffer\ count:\ %d\\n\",\ req.count)\;\n\ \ \ \ fflush(stdout)\;\n\n\ \ \ \ struct\ v4l2_streamparm\ streamparm\ =\ \{0\}\;\n\ \ \ \ streamparm.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_G_PARM,\ &streamparm)\ ==\ -1)\ quit(\"VIDIOC_G_PARM\")\;\n\ \ \ \ if\ (streamparm.parm.capture.capability\ &\ V4L2_CAP_TIMEPERFRAME)\ \{\n\ \ \ \ \ \ \ \ int\ req_rate_numerator\ =\ 1\;\n\ \ \ \ \ \ \ \ int\ req_rate_denominator\ =\ 60\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator\ =\ req_rate_numerator\;\n\ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ =\ req_rate_denominator\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_S_PARM,\ &streamparm)\ ==\ -1)\ \{\ quit(\"VIDIOC_S_PARM\")\;\ \}\n\n\ \ \ \ \ \ \ \ if\ (streamparm.parm.capture.timeperframe.numerator\ !=\ req_rate_numerator\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator\ !=\ req_rate_denominator)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"the\ driver\ changed\ the\ time\ per\ frame\ from\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"%d/%d\ to\ %d/%d\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ req_rate_numerator,\ req_rate_denominator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.numerator,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ streamparm.parm.capture.timeperframe.denominator)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ size_t\ buf_max\ =\ 0\;\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QUERYBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ quit(\"VIDIOC_QUERYBUF\")\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (buf.length\ >\ buf_max)\ buf_max\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].length\ =\ buf.length\;\n\ \ \ \ \ \ \ \ camera->buffers\[i\].start\ =\ \n\ \ \ \ \ \ \ \ \ \ mmap(NULL,\ buf.length,\ PROT_READ\ |\ PROT_WRITE,\ MAP_SHARED,\n\ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ buf.m.offset)\;\n\ \ \ \ \ \ \ \ if\ (camera->buffers\[i\].start\ ==\ MAP_FAILED)\ quit(\"mmap\")\;\n\ \ \ \ \}\n\ \ \ \ camera->head.start\ =\ malloc(buf_max)\;\n\n\ \ \ \ printf(\"camera\ %d\;\ bufcount\ %zu\\n\",\ camera->fd,\ camera->buffer_count)\;\n\}\n\n\$camc\ proc\ cameraStart\ \{Camera*\ camera\}\ void\ \{\n\ \ \ \ for\ (size_t\ i\ =\ 0\;\ i\ <\ camera->buffer_count\;\ i++)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ buf.index\ =\ i\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ quit(\"VIDIOC_QBUF\")\;\n\ \ \ \ \ \ \ \ printf(\"camera_start(%zu):\ %s\\n\",\ i,\ strerror(errno))\;\n\ \ \ \ \}\n\n\ \ \ \ enum\ v4l2_buf_type\ type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_STREAMON,\ &type)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ quit(\"VIDIOC_STREAMON\")\;\n\ \ \ \ \}\n\}\n\n\$camc\ code\ \{\n\ \ \ \ int\ camera_capture(Camera*\ camera)\ \{\n\ \ \ \ \ \ \ \ struct\ v4l2_buffer\ buf\;\n\ \ \ \ \ \ \ \ memset(&buf,\ 0,\ sizeof\ buf)\;\n\ \ \ \ \ \ \ \ buf.type\ =\ V4L2_BUF_TYPE_VIDEO_CAPTURE\;\n\ \ \ \ \ \ \ \ buf.memory\ =\ V4L2_MEMORY_MMAP\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_DQBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_DQBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ memcpy(camera->head.start,\ camera->buffers\[buf.index\].start,\ buf.bytesused)\;\n\ \ \ \ \ \ \ \ camera->head.length\ =\ buf.bytesused\;\n\ \ \ \ \ \ \ \ if\ (xioctl(camera->fd,\ VIDIOC_QBUF,\ &buf)\ ==\ -1)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera_capture:\ VIDIOC_QBUF\ failed:\ %d:\ %s\\n\",\ errno,\ strerror(errno))\;\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 0\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ 1\;\n\ \ \ \ \}\n\}\n\n\$camc\ proc\ cameraFrameJpeg\ \{Camera*\ camera\}\ CameraBuffer\ \{\n\ \ \ \ //\ Retry\ select()\ up\ to\ 5\ times\ with\ 2\ second\ timeout\ each\n\ \ \ \ //\ Some\ cameras\ need\ time\ to\ start\ streaming\n\ \ \ \ int\ r\ =\ 0\;\n\ \ \ \ for\ (int\ attempt\ =\ 0\;\ attempt\ <\ 5\ &&\ r\ ==\ 0\;\ attempt++)\ \{\n\ \ \ \ \ \ \ \ struct\ timeval\ timeout\;\n\ \ \ \ \ \ \ \ timeout.tv_sec\ =\ 2\;\n\ \ \ \ \ \ \ \ timeout.tv_usec\ =\ 0\;\n\ \ \ \ \ \ \ \ fd_set\ fds\;\n\ \ \ \ \ \ \ \ FD_ZERO(&fds)\;\n\ \ \ \ \ \ \ \ FD_SET(camera->fd,\ &fds)\;\n\ \ \ \ \ \ \ \ r\ =\ select(camera->fd\ +\ 1,\ &fds,\ 0,\ 0,\ &timeout)\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ -1)\ quit(\"select\")\;\n\ \ \ \ \ \ \ \ if\ (r\ ==\ 0\ &&\ attempt\ <\ 4)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ fprintf(stderr,\ \"camera/usb:\ select\ timeout\ on\ fd\ %d,\ retry\ %d/4\\n\",\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ camera->fd,\ attempt\ +\ 1)\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ if\ (r\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ FOLK_ERROR(\"selection\ failed\ of\ fd\ %d\ after\ 5\ attempts\\n\",\ camera->fd)\;\n\ \ \ \ \}\n\n\ \ \ \ FOLK_ENSURE(camera_capture(camera)\ !=\ 0)\;\n\n\ \ \ \ //\ Clone\ the\ head\ buffer\ into\ a\ new\ independent\ buffer\ that\ can\ be\n\ \ \ \ //\ owned\ by\ the\ caller.\n\ \ \ \ CameraBuffer\ buf\ =\ \{\n\ \ \ \ \ \ \ \ .start\ =\ malloc(camera->head.length),\n\ \ \ \ \ \ \ \ .length\ =\ camera->head.length\n\ \ \ \ \}\;\n\ \ \ \ memcpy(buf.start,\ camera->head.start,\ buf.length)\;\n\ \ \ \ return\ buf\;\n\}\n\$camc\ proc\ jpegFree\ \{CameraBuffer\ jpeg\}\ void\ \{\n\ \ \ \ free(jpeg.start)\;\n\}\n\n\$camc\ proc\ setExposure\ \{Camera*\ camera\ int\ value\}\ void\ \{\n\ \ \ \ struct\ v4l2_control\ c\;\n\n\ \ \ \ fprintf(stderr,\ \"setExposure\ %d\\n\",\ value)\;\n\ \ \ \ if\ (value\ ==\ 0)\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_APERTURE_PRIORITY\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_AUTO\;\n\ \ \ \ \ \ \ \ c.value\ =\ V4L2_EXPOSURE_MANUAL\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\n\ \ \ \ \ \ \ \ c.id\ =\ V4L2_CID_EXPOSURE_ABSOLUTE\;\n\ \ \ \ \ \ \ \ c.value\ =\ value\;\n\ \ \ \ \ \ \ \ FOLK_ENSURE(xioctl(camera->fd,\ VIDIOC_S_CTRL,\ &c)\ ==\ 0)\;\n\ \ \ \ \}\n\}\n\n\$camc\ cflags\ -Wall\ -Werror\nset\ camLib\ \[\$camc\ compile\]\n\nWhen\ camera\ /cameraPath/\ has\ width\ /decompWidth/\ height\ /decompHeight/\ \{\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ grayImage\ \[\$jpegLib\ jpegDecompressGray\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ gray-frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ gray\ frame\ \$grayImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$grayImage\]\n\ \ \ \ \}\n\ \ \ \ When\ camera\ \$cameraPath\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /ts/\ \{\n\ \ \ \ \ \ \ \ set\ frameImage\ \[\$jpegLib\ jpegDecompressRGB\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$decompWidth\ \$decompHeight\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{int(\$ts\ *\ 1000)\}\]\]\n\ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cameraPath\ frame\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cameraPath\ has\ frame\ \$frameImage\ at\ timestamp\ \$ts\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$frameImage\]\n\ \ \ \ \}\n\}\n\nWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...options/\ \{\n\ \ \ \ if\ \{!\[string\ match\ \"/dev/*\"\ \$camera\]\}\ \{\ return\ \}\n\n\ \ \ \ set\ width\ \[dict\ get\ \$options\ width\]\n\ \ \ \ set\ height\ \[dict\ get\ \$options\ height\]\n\ \ \ \ set\ bufferCount\ \[dict\ getdef\ \$options\ bufferCount\ 2\]\n\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ set\ crops\ \[dict\ get\ \$options\ crops\]\n\ \ \ \ \}\n\n\ \ \ \ fn\ runCamera\ \{camObjVar\}\ \{\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Will\ try\ to\ open\ \$camera\"\n\n\ \ \ \ \ \ \ \ upvar\ \$camObjVar\ camObj_\n\ \ \ \ \ \ \ \ set\ camObj_\ \[\$camLib\ cameraOpen\ \$camera\ \$width\ \$height\]\n\ \ \ \ \ \ \ \ set\ camObj\ \$camObj_\ \;#\ HACK:\ we\ don't\ capture\ upvars\ yet.\n\ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Loaded\ \$camera\ ->\ \$camObj\"\n\n\ \ \ \ \ \ \ \ \$camLib\ cameraInit\ \$camObj\ \$bufferCount\n\ \ \ \ \ \ \ \ \$camLib\ cameraStart\ \$camObj\n\ \ \ \ \ \ \ \ #\ skip\ 5\ frames\ for\ booting\ a\ cam\n\ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ 5\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraFrameJpeg\ \$camObj\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \[list\ \$camera\ \$i\]\ has\ width\ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[dict\ get\ \$crop\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ width\ \$width\ height\ \$height\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ camera\ \$camera\ uses\ exposure\ time\ /exposureTimeUs/\ us\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ setExposure\ \$camObj\ \[expr\ \{int(\$exposureTimeUs\ /\ 100)\}\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Inner,\ frame\ loop.\n\ \ \ \ \ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneBegin\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ms\ \[clock\ milliseconds\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ jpeg\ \[\$camLib\ cameraFrameJpeg\ \$camObj\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ timestamp\ \[expr\ \{\$ms\ /\ 1000.0\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneName\ \"camera/usb:\ \$timestamp\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$crops\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ crop\ \[lindex\ \$crops\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropPath\ \[list\ \$camera\ \$i\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ croppedJpeg\ \[\$jpegLib\ jpegSubimage\ \$jpeg\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ x\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ y\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$crop\ height\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$cropPath\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$cropPath\ has\ jpeg\ frame\ \$croppedJpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$croppedJpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Always\ publish\ the\ source\ jpeg\ so\ the\ preview\ keeps\ working\n\ \ \ \ \ \ \ \ \ \ \ \ #\ even\ when\ virtual\ crops\ are\ configured.\ Gray/RGB\ decompressors\n\ \ \ \ \ \ \ \ \ \ \ \ #\ on\ the\ source\ camera\ are\ gated\ off\ in\ crops\ mode\ to\ avoid\n\ \ \ \ \ \ \ \ \ \ \ \ #\ full-resolution\ decoding.\n\ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ camera\ \$camera\ jpeg\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ camera\ \$camera\ has\ jpeg\ frame\ \$jpeg\ at\ timestamp\ \$timestamp\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -destructor\ \[list\ \$camLib\ jpegFree\ \$jpeg\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ tracy\ zoneEnd\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Outer,\ retry\ loop.\n\ \ \ \ while\ true\ \{\n\ \ \ \ \ \ \ \ set\ camObj\ \{\}\n\ \ \ \ \ \ \ \ try\ -signal\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ runCamera\ camObj\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Error\ \$e\"\n\ \ \ \ \ \ \ \ \}\ on\ signal\ sig\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"camera/usb:\ Signal\ \$sig\"\n\ \ \ \ \ \ \ \ \ \ \ \ #\ This\ is\ actually\ a\ termination\ condition.\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ finally\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$camObj\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"camera/usb:\ Close\ \$camObj\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$camLib\ cameraClose\ \$camObj\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ We\ only\ get\ down\ here\ if\ something\ goes\ wrong.\ Wait\ before\n\ \ \ \ \ \ \ \ #\ trying\ to\ restart\ the\ camera.\n\ \ \ \ \ \ \ \ sleep\ 1\n\ \ \ \ \}\n\}\n\n\}\n
<unknown> claims builtin-programs/camera/slice.folk has program code #\ Example\ program,\ i.e\ the\ (
[ m206:0 (s311:0) ]
)<unknown> claims builtin-programs/camera/slice.folk has program code #\ Example\ program,\ i.e\ the\ public\ API\n#\n#\ When\ \$this\ has\ camera\ slice\ /slice/\ \{\n#\ \ \ \ \ Wish\ \$this\ displays\ camera\ slice\ \$slice\n#\ \}\n\n#\ Callback:\ extract\ out\ a\ camera\ slice\nWhen\ the\ image\ library\ is\ /imageLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ /someone/\ wishes\ /p/\ has\ camera\ slice\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ intrinsics\ /cameraIntrinsics/\ &\\\n\ \ \ \ \ camera\ /cam/\ has\ frame\ /frame/\ at\ timestamp\ /timestamp/\ &\\\n\ \ \ \ \ /p/\ has\ quad\ /q/\ \{\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ ::math::linearalgebra::norm\ \\\n\n\ \ \ \ set\ fWidth\ \[\$imageLib\ Image_width\ \$frame\]\n\ \ \ \ set\ fHeight\ \[\$imageLib\ Image_height\ \$frame\]\n\ \ \ \ #\ Convert\ quad\ to\ camera\ coordinates\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"quadChange\"\n\ \ \ \ set\ q\ \[quadChange\ \$q\ \$cam\]\n\ \ \ \ set\ vertices\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \$poseLib\ project\ \$cameraIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$fWidth\ \$fHeight\ \$v\n\ \ \ \ \}\]\n\ \ \ \ tracy\ zoneEnd\n\n\ \ \ \ lassign\ \[\$quadLib\ vertices\ \$q\]\ topLeft\ topRight\ bottomRight\ bottomLeft\n\ \ \ \ #\ These\ dimensions\ are\ in\ meters.\ We\ have\ to\ start\ from\ these\ quad\n\ \ \ \ #\ dimensions\ (not\ projected\ camera-plane\ dimensions)\ to\ maintain\n\ \ \ \ #\ aspect\ ratio.\n\ \ \ \ set\ quadWidth\ \[::math::max\ \[norm\ \[sub\ \$topRight\ \$topLeft\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRight\ \$bottomLeft\]\]\]\n\ \ \ \ set\ quadHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRight\ \$topRight\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeft\ \$topLeft\]\]\]\n\n\ \ \ \ #\ Scale\ quadWidth\ and\ quadHeight\ to\ appropriate\ pixel\ dimensions\n\ \ \ \ #\ by\ finding\ the\ scale\ factor\ from\ projected\ vertices\n\ \ \ \ lassign\ \$vertices\ topLeftProj\ topRightProj\ bottomRightProj\ bottomLeftProj\n\ \ \ \ set\ projectedWidth\ \[::math::max\ \[norm\ \[sub\ \$topRightProj\ \$topLeftProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomRightProj\ \$bottomLeftProj\]\]\]\n\ \ \ \ set\ projectedHeight\ \[::math::max\ \[norm\ \[sub\ \$bottomRightProj\ \$topRightProj\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[norm\ \[sub\ \$bottomLeftProj\ \$topLeftProj\]\]\]\n\n\ \ \ \ #\ Use\ the\ larger\ dimension\ to\ determine\ pixels\ per\ meter\n\ \ \ \ set\ maxProjected\ \[::math::max\ \$projectedWidth\ \$projectedHeight\]\n\ \ \ \ set\ max3D\ \[::math::max\ \$quadWidth\ \$quadHeight\]\n\ \ \ \ set\ pixelsPerMeter\ \[expr\ \{\$maxProjected\ /\ \$max3D\}\]\n\n\ \ \ \ #\ Scale\ to\ pixels\ while\ maintaining\ aspect\ ratio\n\ \ \ \ set\ sliceWidth\ \[expr\ \{int(\$quadWidth\ *\ \$pixelsPerMeter)\}\]\n\ \ \ \ set\ sliceHeight\ \[expr\ \{int(\$quadHeight\ *\ \$pixelsPerMeter)\}\]\n\n\ \ \ \ tracy\ zoneBegin\n\ \ \ \ tracy\ zoneName\ \"warpQuad\"\n\ \ \ \ set\ slice\ \[\$imageLib\ warpQuad\ \$frame\ \$vertices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$sliceWidth\ \$sliceHeight\]\n\ \ \ \ tracy\ zoneEnd\n\ \ \ \ Claim\ \$p\ has\ camera\ slice\ \$slice\ \\\n\ \ \ \ \ \ \ \ -destructor\ \[list\ \$imageLib\ imageFree\ \$slice\]\n\}\n\n#\ Auto-trigger\ callback\ for\ `when\ has\ camera\ slice`\ statements\nWhen\ when\ /p/\ has\ camera\ slice\ /slice/\ /lambda/\ with\ environment\ /e/\ \{\n\ \ \ \ Wish\ -nonatomically\ \$p\ has\ camera\ slice\n\}\n\n#\ Display\ a\ camera\ slice\ (for\ backward\ compatibility).\nWhen\ /someone/\ wishes\ /p/\ displays\ camera\ slice\ /slice/\ \{\n\ \ \ \ Wish\ \$p\ displays\ image\ \$slice\n\}\n
<unknown> claims the default program geometry is {tagSize 30mm left 151mm right 30mm top 30mm bottom (
[ m925:0 (s1606:0) ]
[ m926:0 (s1607:0) ]
[ m927:0 () ]
)<unknown> claims the default program geometry is {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}
<unknown> claims 62 has program code {Claim the animation toy's frame count is 6
Claim the animation (
[ m47946:638 (s15550:765) ]
)<unknown> claims 62 has program code {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 8
}
<unknown> claims 11 has program code {Wish $this displays image "https://blob.gifcities.org/gifcities (
[ m33928:727 (s14336:866) ]
)<unknown> claims 11 has program code {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}
<unknown> claims 54 has program code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ i (
[ m6504:986 (s53020:1175) ]
)<unknown> claims 54 has program code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
<unknown> claims 82 has program code When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ (
[ m6717:990 (s53276:1175) ]
)<unknown> claims 82 has program code When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n
<unknown> claims 63 has program code {When $this has camera slice /slice/ {
Wish $this displays cam (
[ m3370:1022 (s32221:1214) ]
)<unknown> claims 63 has program code {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
<unknown> claims 83 has program code {Claim $this is a viewport
} (
[ m47707:1063 (s64458:1262) ]
)<unknown> claims 83 has program code {Claim $this is a viewport
}
<unknown> wishes camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposure ti (
[ m1679:0 () ]
)<unknown> wishes camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 uses exposure time 6800 us
<unknown> wishes folk-sva uses display monitor with width 4096 height 2160 refreshRate 60000 (
[ m61849:1040 () ]
[ m61939:1052 () ]
)<unknown> wishes folk-sva uses display monitor with width 4096 height 2160 refreshRate 60000
<unknown> wishes folk-sva uses display monitor with width 1920 height 1200 refreshRate 60000 (
[ m61846:1044 () ]
[ m61938:1049 () ]
)<unknown> wishes folk-sva uses display monitor with width 1920 height 1200 refreshRate 60000
<unknown> wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 wi (
[ m942:0 () ]
[ m1502:0 (s2605:0 s2606:0) ]
[ m61912:1053 () ]
[ m62009:1055 () ]
)<unknown> wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with width 1920 height 1080 framerate 60.0
<unknown> wishes program 54 is replaced with code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWi (
[ m6503:990 (s53017:1175) ]
[ m6517:989 (s53033:1175) ]
[ m6590:987 () ]
)<unknown> wishes program 54 is replaced with code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n editedTime 1778274042
<unknown> wishes program 83 is replaced with code {Claim $this is a viewport
Wish $this is outlined w (
[ m47719:1064 (s64471:1258) ]
[ m47722:1059 (s64483:1262) ]
[ m47777:1063 () ]
)<unknown> wishes program 83 is replaced with code {Claim $this is a viewport
Wish $this is outlined white} editedTime 1781548209
<unknown> wishes program 62 is replaced with code {Claim the animation toy's frame count is 6
Claim t (
[ m47944:642 (s15546:766) ]
[ m47961:638 (s15567:766) ]
[ m48159:639 () ]
)<unknown> wishes program 62 is replaced with code {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 4
} editedTime 1778278213
<unknown> wishes 62 is titled {(edited Fri, 08 May 2026, 10:10 PM)} (
[ m3187:1024 () ]
[ m44164:1028 () ]
[ m19230:1047 () ]
[ m21715:1048 () ]
[ m16204:1053 () ]
)<unknown> wishes 62 is titled {(edited Fri, 08 May 2026, 10:10 PM)}
<unknown> wishes 54 is titled {(edited Fri, 08 May 2026, 09:00 PM)} (
[ m28117:1064 () ]
[ m29177:1066 () ]
[ m30118:1067 () ]
)<unknown> wishes 54 is titled {(edited Fri, 08 May 2026, 09:00 PM)}
<unknown> wishes 83 is titled {(edited Mon, 15 Jun 2026, 06:30 PM)} (
[ m47911:1063 () ]
[ m53689:1037 () ]
[ m13891:1063 () ]
[ m40615:1065 () ]
[ m44014:1044 () ]
[ m52168:1044 () ]
[ m2157:1066 () ]
[ m30985:1067 () ]
)<unknown> wishes 83 is titled {(edited Mon, 15 Jun 2026, 06:30 PM)}
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/la (
[ m216:0 (s321:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/laser.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/po (
[ m212:0 (s335:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/points-at.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ma (
[ m217:0 (s322:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/mask-tags.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/mu (
[ m215:0 (s318:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/music.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gr (
[ m209:0 (s320:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/group.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ke (
[ m213:0 (s325:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/pr (
[ m214:0 (s336:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/programs.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/er (
[ m211:0 (s317:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/errors.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/te (
[ m210:0 (s319:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/terminal.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m218:0 (s323:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/demos.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/in (
[ m266:0 (s404:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/intersect.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ta (
[ m277:0 (s420:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/tags-to-quads.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ap (
[ m279:0 (s429:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/apriltags.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m282:0 (s435:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/regions.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/te (
[ m283:0 (s436:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/terminal-ui.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sh (
[ m287:0 (s442:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/shapes.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sp (
[ m291:0 (s449:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sprites.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ke (
[ m294:0 (s454:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/keyboard.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/es (
[ m295:0 (s452:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/esc-pos.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/au (
[ m302:0 (s470:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/audio.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ta (
[ m325:0 (s505:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/tags-geometry.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ti (
[ m334:0 (s520:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/title.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/co (
[ m335:0 (s522:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/connections.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/un (
[ m337:0 (s526:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/unix-commands.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/fs (
[ m357:0 (s555:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/fswatch.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m369:0 (s579:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor-control.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m374:0 (s586:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display-saver.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m384:0 (s607:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/image.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m395:0 (s618:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/apriltags.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m403:0 (s636:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/fill.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m406:0 (s643:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/dashed-line.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m410:0 (s653:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/line.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m421:0 (s670:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/gif.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m431:0 (s687:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/circle.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m437:0 (s697:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/color-map.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m441:0 (s708:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/gif-lib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m443:0 (s712:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/text.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m447:0 (s716:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m454:0 (s727:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/image-lib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m472:0 (s753:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/png-lib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/pr (
[ m473:0 (s751:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/print/print.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m475:0 (s756:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/dep-graph.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m491:0 (s781:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/nav.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m495:0 (s789:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/setup.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m501:0 (s800:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/block-stats.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m503:0 (s798:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/textures.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m515:0 (s823:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/program.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m523:0 (s830:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/holds.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m531:0 (s842:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/db-lib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m535:0 (s845:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/threads.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m544:0 (s859:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/web.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m550:0 (s866:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/quads.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m559:0 (s878:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/statements.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m569:0 (s892:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/keyboards.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m579:0 (s903:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/trie-graph.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m581:0 (s906:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/page.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m593:0 (s923:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/atomicallys.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m599:0 (s932:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/new.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m607:0 (s943:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/log.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m615:0 (s954:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/camera-frame.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m621:0 (s963:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m627:0 (s972:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/report.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m633:0 (s981:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/printed-programs.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m641:0 (s992:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/index.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m649:0 (s1003:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/camera.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m657:0 (s1014:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m663:0 (s1024:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m682:0 (s1052:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m688:0 (s1061:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/model.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m694:0 (s1070:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m700:0 (s1079:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/refine.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m706:0 (s1088:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/enumerate.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m712:0 (s1096:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/matlib.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m718:0 (s1105:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m725:0 (s1117:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/pipelines.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m731:0 (s1126:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/gpu.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m738:0 (s1137:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/textures.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m745:0 (s1147:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/draw.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m751:0 (s1156:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m759:0 (s1167:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/canvases.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m765:0 (s1176:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/vma.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m850:0 (s1307:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sh (
[ m856:0 (s1318:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/shapes/region.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m862:0 (s1329:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display/arc.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m868:0 (s1339:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display/curve.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m874:0 (s1352:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/trocr.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m880:0 (s1362:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/sam2.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m886:0 (s1372:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/craft.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m892:0 (s1382:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/contours.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m842:0 (s1296:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/save-holds.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m832:0 (s1283:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/migrate.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m821:0 (s1263:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/saving.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m815:0 (s1254:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/save-programs.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m809:0 (s1244:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/print-editor.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m803:0 (s1234:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/editor.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m796:0 (s1224:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/editor-utils.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m790:0 (s1215:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/draw-editor.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m784:0 (s1206:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/decorations/outline.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m778:0 (s1196:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/decorations/label.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m772:0 (s1187:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/rpi.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m368:0 (s576:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/enumerate.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m284:0 (s439:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/slice.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m219:0 (s324:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/usb.folk does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ke (
[ m236:0 (s364:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/te (
[ m238:0 (s369:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ma (
[ m240:0 (s370:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m239:0 (s368:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/demos.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/er (
[ m241:0 (s374:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/errors.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gr (
[ m243:0 (s379:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/group.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/la (
[ m249:0 (s385:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/laser.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/mu (
[ m253:0 (s391:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/music.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m256:0 (s394:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/po (
[ m261:0 (s398:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/pr (
[ m263:0 (s400:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/programs.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/in (
[ m281:0 (s434:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m300:0 (s463:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/regions.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/te (
[ m303:0 (s478:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ap (
[ m307:0 (s481:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sp (
[ m310:0 (s484:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/es (
[ m312:0 (s485:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ke (
[ m320:0 (s499:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sh (
[ m321:0 (s502:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ta (
[ m330:0 (s513:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/au (
[ m338:0 (s527:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/audio.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m343:0 (s531:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ta (
[ m350:0 (s549:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/co (
[ m353:0 (s554:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/connections.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ti (
[ m355:0 (s552:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/title.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/un (
[ m361:0 (s565:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/fs (
[ m372:0 (s583:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m381:0 (s599:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m382:0 (s602:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m386:0 (s609:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m394:0 (s617:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m400:0 (s625:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {tag /any/ has a program} with settle 0ms (
[ m405:0 (s641:0) ]
)builtin-programs/collect.folk wishes to collect results for {tag /any/ has a program} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m414:0 (s660:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m418:0 (s665:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/loader/ is an image loader} with settle (
[ m424:0 (s675:0) ]
)builtin-programs/collect.folk wishes to collect results for {/loader/ is an image loader} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m428:0 (s684:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m432:0 (s688:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m442:0 (s707:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m448:0 (s719:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m456:0 (s731:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m459:0 (s735:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/dr (
[ m463:0 (s742:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m467:0 (s745:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/im (
[ m480:0 (s768:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m481:0 (s767:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/pr (
[ m483:0 (s771:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m498:0 (s793:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes the web server handles (
[ m507:0 (s806:0) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes the web server handles route /route/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m509:0 (s813:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m514:0 (s820:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m516:0 (s819:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m529:0 (s835:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m533:0 (s844:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m543:0 (s856:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m548:0 (s864:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m556:0 (s874:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m558:0 (s880:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m566:0 (s887:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m573:0 (s897:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m584:0 (s914:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m586:0 (s916:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m596:0 (s928:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m602:0 (s937:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m610:0 (s948:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m618:0 (s959:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m624:0 (s968:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m630:0 (s977:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m636:0 (s986:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m644:0 (s997:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/we (
[ m652:0 (s1008:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m660:0 (s1019:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m666:0 (s1029:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/somebody/ claims the default program ge (
[ m670:0 (s1037:0) ]
)builtin-programs/collect.folk wishes to collect results for {/somebody/ claims the default program geometry is /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera / (
[ m680:0 (s1047:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera /cam/ to display /disp/ is /anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m685:0 (s1057:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m691:0 (s1066:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m697:0 (s1075:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m703:0 (s1084:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m709:0 (s1093:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m715:0 (s1101:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m721:0 (s1110:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m728:0 (s1122:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m734:0 (s1131:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m741:0 (s1142:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m748:0 (s1152:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m754:0 (s1161:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m762:0 (s1172:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m768:0 (s1181:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ca (
[ m775:0 (s1192:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m781:0 (s1201:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/de (
[ m787:0 (s1211:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m793:0 (s1220:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m799:0 (s1229:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m806:0 (s1239:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/ed (
[ m812:0 (s1249:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m818:0 (s1259:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m824:0 (s1268:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m835:0 (s1288:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sa (
[ m845:0 (s1301:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gp (
[ m853:0 (s1312:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/sh (
[ m859:0 (s1323:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m865:0 (s1334:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/di (
[ m871:0 (s1344:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m877:0 (s1357:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m883:0 (s1367:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m889:0 (s1377:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/re (
[ m895:0 (s1387:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes to calibrate camera /any/ t (
[ m1026:0 (s1802:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ detects tags /tags/ on camera (
[ m1029:0 (s1806:0) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ detects tags /tags/ on camera /camera/ at timestamp /timestamp/ in time /aprilTime/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera / (
[ m1064:0 (s1852:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera /camera/ to display /display/ is /anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes folk-sva uses display glfw (
[ m1098:0 (s1893:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes folk-sva uses display glfw with /...any/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {the changer from space /sourceSpace/ to (
[ m1401:0 (s2265:0) ]
)builtin-programs/collect.folk wishes to collect results for {the changer from space /sourceSpace/ to space /targetSpace/ is /changer/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera / (
[ m4496:0 (s6299:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is /anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera / (
[ m23660:0 (s31349:0) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ claims a calibration from camera /cam/ to display monitor is /anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 62 does not run} wi (
[ m47951:637 (s15557:766) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 62 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 62 is replaced with (
[ m48153:638 (s15793:766) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 62 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 11 does not run} wi (
[ m33931:727 (s14338:856) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 11 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 11 is replaced with (
[ m33937:727 (s14347:851) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 11 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 11 has geometry /ge (
[ m25657:915 (s2788:1088) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 11 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is labelled /text/ w (
[ m25757:915 (s2899:1083) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 82 has geometry /ge (
[ m6394:989 (s52873:1174) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 82 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 54 does not run} wi (
[ m6511:990 (s53025:1175) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 54 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 54 is replaced with (
[ m6582:986 (s53125:1175) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 54 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 82 does not run} wi (
[ m6721:979 (s53278:1175) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 82 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 82 is replaced with (
[ m6729:979 (s53290:1175) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 82 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is labelled /text/ w (
[ m6752:990 (s53316:1175) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 62 has geometry /ge (
[ m3059:1024 (s31839:1214) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 62 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is labelled /text/ w (
[ m3091:1024 (s31883:1215) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 63 does not run} wi (
[ m3372:1022 (s32223:1215) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 63 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 63 is replaced with (
[ m3375:1022 (s32228:1214) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 63 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is left-marg (
[ m44360:1038 (s51510:1233) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is right-mar (
[ m44366:1038 (s51518:1233) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is footnoted (
[ m44373:1035 (s51528:1233) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is titled /t (
[ m44378:1034 (s51537:1233) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 63 has geometry /ge (
[ m44639:1032 (s51835:1233) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 63 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is labelled /text/ w (
[ m44684:1039 (s51885:1229) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is left-margined /te (
[ m16189:1052 (s40286:1249) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is right-margined /t (
[ m16194:1053 (s40291:1249) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is footnoted /text/} (
[ m16199:1048 (s40295:1248) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is titled /text/} wi (
[ m16203:1053 (s40298:1249) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 62 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is left-margined /te (
[ m16436:1044 (s40611:1194) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is titled /text/} wi (
[ m16465:1051 (s40618:1195) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is right-margined /t (
[ m16466:1048 (s40619:1248) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is footnoted /text/} (
[ m16475:1050 (s40627:1194) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 63 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {folk-sva has display /display/ with /... (
[ m61803:1036 (s49325:1252) ]
)builtin-programs/collect.folk wishes to collect results for {folk-sva has display /display/ with /...opts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wis (
[ m61816:1044 (s49342:1241) ]
)builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses display m (
[ m61825:1042 (s49351:1252) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {folk-sva has camera /camera/ with /...op (
[ m61858:1037 (s49386:1248) ]
)builtin-programs/collect.folk wishes to collect results for {folk-sva has camera /camera/ with /...opts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wis (
[ m61883:1047 (s49421:1249) ]
)builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /d (
[ m61891:975 (s49427:1236) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wis (
[ m61897:1055 (s49435:1252) ]
)builtin-programs/collect.folk wishes to collect results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /d (
[ m61907:1048 (s49444:1252) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses display / (
[ m61932:1052 (s49464:1250) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses display /display/ with /...opts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /c (
[ m62005:1055 (s49550:1245) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is titled /text/} wi (
[ m17867:1058 (s28222:1254) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is left-margined /te (
[ m17875:1058 (s28230:1240) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is right-margined /t (
[ m17882:1053 (s28244:1239) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is footnoted /text/} (
[ m17884:1057 (s28249:1245) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 82 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is left-margined /te (
[ m23204:1061 (s14509:1257) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is right-margined /t (
[ m23213:1061 (s14515:1260) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is footnoted /text/} (
[ m23222:1061 (s14526:1256) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is titled /text/} wi (
[ m23228:1059 (s14530:1259) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 11 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 54 has geometry /ge (
[ m23348:1059 (s14675:1259) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 54 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is labelled (
[ m23385:1039 (s14729:1259) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is labelled (
[ m23390:1062 (s14735:1259) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is labelled (
[ m23400:1062 (s14745:1220) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is labelled (
[ m23406:1062 (s14752:1222) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is labelled (
[ m23411:1062 (s14758:1257) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is labelled (
[ m23418:1062 (s14764:1260) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is labelled (
[ m23430:1062 (s14776:1223) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-display is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is labelled /text/ w (
[ m23485:1060 (s14838:1260) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-6 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is titled /text/} wi ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is left-margined /te ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is right-margined /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is footnoted /text/} ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 83 has geometry /ge (
[ m47703:1064 (s64452:1262) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ claims tag 83 has geometry /geom/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 83 does not run} wi (
[ m47713:1064 (s64467:990) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 83 does not run} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 83 is replaced with (
[ m47774:1064 (s64538:1262) ]
)builtin-programs/collect.folk wishes to collect results for {/any/ wishes program 83 is replaced with /...anything/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is labelled /text/ w (
[ m47784:1064 (s64549:1258) ]
)builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is labelled /text/ with /...options/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-5 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-1 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-4 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-2 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is left-marg ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is right-mar ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is footnoted ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is titled /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 54-frame-3 is titled /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is left-margined /te ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is left-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is right-margined /t ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is right-margined /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is footnoted /text/} ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is footnoted /text/} with settle 0ms
builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is titled /text/} wi ()builtin-programs/collect.folk wishes to collect results for {/someone/ wishes 83 is titled /text/} with settle 0ms
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m220:0 (s352:0 s367:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/usb.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m221:0 (s340:0 s347:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/terminal.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m223:0 (s342:0 s348:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/errors.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m222:0 (s339:0 s345:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m224:0 (s341:0 s346:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/mask-tags.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m225:0 (s351:0 s363:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/music.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m226:0 (s343:0 s349:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/demos.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m227:0 (s344:0 s353:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/group.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m228:0 (s350:0 s361:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/laser.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m229:0 (s360:0 s371:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/points-at.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m230:0 (s359:0 s366:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/programs.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m248:0 (s377:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/keyboard-shortcuts.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m250:0 (s384:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/terminal.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m252:0 (s383:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/demos.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m254:0 (s387:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/mask-tags.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m255:0 (s390:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/errors.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m257:0 (s392:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/group.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m264:0 (s401:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/laser.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m267:0 (s403:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/music.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m268:0 (s409:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/usb.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m269:0 (s406:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/points-at.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m272:0 (s412:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/programs.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m275:0 (s418:0 s423:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/intersect.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m280:0 (s476:0 s496:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m285:0 (s457:0 s464:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/apriltags.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m288:0 (s444:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/intersect.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m289:0 (s448:0 s450:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/regions.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m290:0 (s453:0 s460:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m293:0 (s469:0 s488:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/shapes.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m297:0 (s462:0 s468:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/sprites.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m298:0 (s465:0 s471:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/esc-pos.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m299:0 (s475:0 s482:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/keyboard.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m305:0 (s472:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/regions.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m311:0 (s501:0 s514:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/audio.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m313:0 (s487:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/terminal-ui.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m315:0 (s497:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/apriltags.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m317:0 (s492:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/esc-pos.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m319:0 (s494:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/sprites.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m324:0 (s508:0 s516:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/slice.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m328:0 (s509:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/keyboard.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m329:0 (s518:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/shapes.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m332:0 (s525:0 s530:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m336:0 (s542:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/tags-to-quads.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m342:0 (s533:0 s538:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/title.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m344:0 (s535:0 s545:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/connections.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m346:0 (s541:0 s550:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/unix-commands.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m345:0 (s540:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/audio.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m349:0 (s546:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/slice.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m359:0 (s561:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/tags-geometry.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m360:0 (s560:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/title.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m363:0 (s564:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/connections.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m362:0 (s568:0 s573:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/fswatch.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m367:0 (s575:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/unix-commands.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m373:0 (s588:0 s592:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m375:0 (s593:0 s598:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor-control.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m376:0 (s589:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/fswatch.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m377:0 (s591:0 s594:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display-saver.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m385:0 (s605:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/enumerate.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m387:0 (s606:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display-saver.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m390:0 (s612:0 s614:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/image.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m391:0 (s611:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor-control.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m396:0 (s621:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/image.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m397:0 (s622:0 s623:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m401:0 (s627:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/apriltags.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m407:0 (s647:0 s649:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/fill.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {tag /any/ has a program} are {{} {} { (
[ m47706:1055 () ]
)builtin-programs/collect.folk claims the collected results for {tag /any/ has a program} are {{} {} {} {} {} {}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m409:0 (s651:0 s656:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m416:0 (s667:0 s673:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/line.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m419:0 (s666:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/fill.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m423:0 (s672:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/dashed-line.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m426:0 (s679:0 s682:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/gif.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/loader/ is an image loader} are {{lo (
[ m1003:0 (s1774:0) ]
)builtin-programs/collect.folk claims the collected results for {/loader/ is an image loader} are {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m433:0 (s692:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/line.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m434:0 (s695:0 s698:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/circle.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m435:0 (s693:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/gif.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m440:0 (s705:0 s711:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m445:0 (s714:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/circle.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m446:0 (s718:0 s722:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m450:0 (s728:0 s734:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/text.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m451:0 (s725:0 s730:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m452:0 (s724:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/color-map.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m457:0 (s736:0 s740:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m461:0 (s739:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/gif-lib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m462:0 (s741:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/jpeg-lib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m468:0 (s747:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/draw/text.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m469:0 (s750:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/image-lib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m474:0 (s760:0 s764:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/print/print.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m476:0 (s758:0 s761:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m477:0 (s759:0 s762:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m484:0 (s774:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/dep-graph.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m485:0 (s775:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/image/png-lib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m486:0 (s776:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/print/print.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m494:0 (s785:0 s788:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/nav.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m499:0 (s804:0 s812:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/setup.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m500:0 (s797:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/nav.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m504:0 (s807:0 s811:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/textures.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m505:0 (s805:0 s808:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes the web server handl (
[ m47727:0 (s60114:0) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes the web server handles route /route/ with /...options/} are {{route /editor-control options {hidden true handler {applyBlock {
html {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Editor copy/paste</title>
<script src="/lib/folk.js"></script>
</head>
<body>
<span id="status">Status</span>
<p>
Select a keyboard: <select id="keyboard-select"></select>
</p>
<textarea id="code" cols="120" rows="40"></textarea>
<script>
const ws = new FolkWS(document.getElementById('status'));
const keyboardSelect = document.querySelector("#keyboard-select");
const textarea = document.querySelector("#code");
var currentKeyboard = null;
var programCode = ""; // not the same as editor code
var cursorPosition = [0, 0];
// temporarily disable event processing after sending new code to prevent recursive event sends
var allowLocalEventsToProcess = true;
var allowRemoteEventsToProcess = true;
var _remoteTimoutHandle;
var _localTimeoutHandle;
function disableRemoteEventProcessing(durationMs) {
if (_remoteTimoutHandle) clearTimeout(_remoteTimoutHandle);
allowRemoteEventsToProcess = false;
_remoteTimoutHandle = setTimeout(() => {
allowRemoteEventsToProcess = true;
}, durationMs);
}
function disableLocalEventProcessing(durationMs) {
if (_localTimeoutHandle) clearTimeout(_localTimeoutHandle);
allowLocalEventsToProcess = false;
_localTimeoutHandle = setTimeout(() => {
allowLocalEventsToProcess = true;
}, durationMs);
}
function updateProgramCode() {
disableRemoteEventProcessing(500);
const { page, kbPath } = currentKeyboard;
const currentCode = textarea.value;
programCode = currentCode;
const id = page + kbPath;
ws.run(tcl`
Hold (non-capturing) (on builtin-programs/editor.folk) ${"cursor" + kbPath} {
Claim the ${kbPath} cursor is [list ${cursorPosition[0]} ${cursorPosition[1]}]
Hold (on builtin-programs/editor.folk) ${"code" + kbPath} {
Claim ${id} has program code [binary decode base64 ${btoa(currentCode)}]
Claim ${id} has editor code [binary decode base64 ${btoa(currentCode)}]
}
}
`);
}
function updateCursorAndCode(ev) {
if (!allowLocalEventsToProcess) return;
disableRemoteEventProcessing(500);
const { page, kbPath } = currentKeyboard;
const newCode = ev.target.value;
// figure out cursor position
const currentPosition = textarea.selectionStart;
const linesBefore = newCode.substring(0, currentPosition).split("\n");
const y = linesBefore.length - 1;
const x = linesBefore[linesBefore.length - 1].length;
cursorPosition = [x, y];
const id = page + kbPath;
ws.run(tcl`
Hold (non-capturing) (on builtin-programs/editor.folk) ${"cursor" + kbPath} {
Claim the ${kbPath} cursor is [list ${x} ${y}]
Hold (on builtin-programs/editor.folk) ${"code" + kbPath} {
Claim ${id} has program code [binary decode base64 ${btoa(programCode)}]
Claim ${id} has editor code [binary decode base64 ${btoa(newCode)}]
}
}
`);
}
textarea.addEventListener("input", updateCursorAndCode);
textarea.addEventListener("selectionchange", updateCursorAndCode);
textarea.addEventListener("keydown", ev => {
if(ev.keyCode === 83 /* s */ && (navigator.platform.match("Mac") ? ev.metaKey : ev.ctrlKey)) {
ev.preventDefault();
updateProgramCode();
}
});
var lastKeyboard; // to clean up the previous keyboard when another is picked
async function selectKeyboard({ page, kbPath }) {
if (lastKeyboard) lastKeyboard.stop();
currentKeyboard = { page, kbPath };
const id = page + kbPath;
lastKeyboard = await ws.watch(`${id} has base64 editor code /editorCode/ program code /programCode/ & the ${kbPath} cursor is /cursor/`, {
add: ({ editorCode, programCode: _programCode, cursor }) => {
if (!allowRemoteEventsToProcess) return;
disableLocalEventProcessing(500);
programCode = atob(_programCode);
editorCode = atob(editorCode);
textarea.value = editorCode;
// figure out where the cursor is
let [x, y] = loadList(cursor);
x = parseInt(x); y = parseInt(y);
cursorPosition = [x, y];
const lines = editorCode.split("\n");
let pos = 0;
for (let i = 0; i < y; i++) {
pos += lines[i].length + 1; // + 1 for newline
}
pos += x;
textarea.focus();
textarea.selectionStart = pos;
textarea.selectionEnd = pos;
}
});
}
// update keyboard list as it changes
ws.watchCollected("/page/ is an editor & /page/ is a keyboard with path /kbPath/", keyboards => {
keyboardSelect.innerHTML = "";
for (let keyboard of keyboards) {
let {page, kbPath} = keyboard;
keyboardSelect.innerHTML += `<option value="${JSON.stringify(keyboard)}">${page} (${kbPath})</option>`;
}
if (keyboards.length === 1) {
selectKeyboard(keyboards[0]);
}
});
// fired when selected keyboard changes
keyboardSelect.addEventListener("input", (ev) => {
selectKeyboard(JSON.parse(ev.target.value));
});
</script>
</body>
</html>
}
} {{this builtin-programs/editor-control.folk} {} {}}}}} {route /block-stats options {handler {applyBlock {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
} {{this builtin-programs/web/block-stats.folk} {} {}}}}} {route /setup options {nav <button>Setup</button> handler {applyBlock \n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n {{this builtin-programs/web/setup.folk} {} {}}}}} {route {/program/(.*)$} options {handler {applyBlock {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
} {{this builtin-programs/web/program.folk} {} {}}}}} {route /quads options {handler {applyBlock {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
} {{this builtin-programs/web/quads.folk} {} {}}}}} {route {/keyboards$} options {handler {applyBlock {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
} {{this builtin-programs/web/keyboards.folk} {} {}}}}} {route {/page/(.*)$} options {handler {applyBlock \n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/page.folk} {} {}}}}} {route /new options {nav {<button>New program</button>} handler {applyBlock \n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n {{this builtin-programs/web/new.folk} {} {}}}}} {route {/log/(.+)$} options {hidden true handler {applyBlock {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
} {{this builtin-programs/web/log.folk} {} {}}}}} {route {/printed-programs/([^/]+)\.folk$} options {handler {applyBlock {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
} {{this builtin-programs/web/printed-programs.folk} {} {}}}}} {route / options {handler {applyBlock \n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/index.folk} {} {}}}}} {route /camera options {handler {applyBlock {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
} {{this builtin-programs/web/camera.folk} {} {}}}}} {route /threads options {handler {applyBlock \n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/threads.folk} {} {threadMonitorLib <C:cfileUfFKg0>}}}}} {route {/trie-graph\.pdf} options {handler {applyBlock \n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n {{this builtin-programs/web/trie-graph.folk} {} {trieDotify {{trieLib tclifiedTrie} {
local proc idify {word} {
# generate id-able word by eliminating all non-alphanumeric
regsub -all {\W+} $word "_"
}
local proc labelify {word} {
# shorten the longest lines
set word [join [lmap line [split $word "\n"] {
expr { [string length $line] > 80 ? "[string range $line 0 80]..." : $line }
}] "\n"]
string map {"\"" "\\\""} [string map {"\\" "\\\\"} $word]
}
local proc subdot {subtrie} {
set branches [lassign $subtrie ptr key id]
set dot [list]
lappend dot "$ptr \[label=\"[labelify $key]\"\];"
foreach branch $branches {
if {$branch eq {}} continue
set branchptr [lindex $branch 0]
lappend dot "$ptr -> $branchptr;"
lappend dot [subdot $branch]
}
return [join $dot "\n"]
}
return "digraph { rankdir=LR; [subdot $tclifiedTrie] }"
}} getDotAsPdf {{dot} {
set fd [open |[list dot -Tpdf <<$dot] rb]
set response [read $fd]
try {
close $fd
return $response
} on error e {
if {[catch {exec which dot}]} {
error "graphviz not installed!"
}
}
}} trieLib <C:cfileUen4B3>}}}}} {route /calibrate/board.pdf options {hidden true handler {applyBlock \n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPng {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}}} {route /calibrate/board.png options {hidden true handler {applyBlock \n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPng {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}}} {route /apriltag-frame options {handler {applyBlock \n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {{this builtin-programs/web/apriltag-frame.folk} {} {} {jpegLib <C:cfileZXB3iE>} {}}}}} {route /camera-frame options {handler {applyBlock \n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ {{this builtin-programs/web/camera-frame.folk} {} {} {jpegLib <C:cfileZXB3iE>} {}}}}} {route /calibrate options {hidden true handler {applyBlock \n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}}}}}} {route {/calibration-poses/([^/]+)$} options {handler {applyBlock \n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}}}}}} {route /textures options {handler {applyBlock {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
} {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {drawLib <C:cfile7Rjpvq>} {} {vmaDll /tmp/cfilequ8HAs.so} {} {gpuTextureLib <C:cfileHQKyt3>} {texturesLib <C:cfile6Gqcwo> cc ::<reference.<C______>.00000000000000000010>}}}}} {route /report options {handler {applyBlock {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
} {{this builtin-programs/web/report.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}}} {route /atomicallys options {handler {applyBlock {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
} {{this builtin-programs/web/atomicallys.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}}} {route /statements options {handler {applyBlock {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
} {{this builtin-programs/web/statements.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}}} {route /holds options {handler {applyBlock {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
} {{this builtin-programs/web/holds.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}}} {route {/dep-graph\.pdf} options {handler {applyBlock \n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ {{this builtin-programs/web/dep-graph.folk} {} {getDotAsPdf {{dot} {
set fd [open |[list dot -Tpdf <<$dot] r]
fconfigure $fd -translation binary
set response [read $fd]
try {
close $fd
return $response
} on error e {
if {[catch {exec which dot}]} {
error "graphviz not installed!"
}
}
}} dbDotify {{dbLib db} {
set dot [list]
set matchRefs [dict create]
foreach stmt [Query! /...anything/] {
set stmtRef [dict get $stmt __ref]
set label [$dbLib clause $db $stmtRef]
set label [join [lmap line [split $label "\n"] {
expr { [string length $line] > 80 ? "[string range $line 0 80]..." : $line }
}] "\n"]
set label [string map {"\"" "\\\""} [string map {"\\" "\\\\"} $label]]
set stmtParentCount [$dbLib statementParentCount $db $stmtRef]
set stmtPtrCount [$dbLib statementPtrCount $db $stmtRef]
lappend dot "<$stmtRef> \[label=\"$stmtRef ($stmtParentCount parents) ($stmtPtrCount ptrs): $label\"\];"
foreach childMatchRef [$dbLib childMatches $db $stmtRef] {
lappend dot "<$stmtRef> -> <$childMatchRef>;"
dict set matchRefs $childMatchRef true
}
}
foreach {matchRef _} $matchRefs {
set match [$dbLib matchAcq $db $matchRef]
if {$match eq "(Match*) 0x0"} { continue }
set matchPtrCount [$dbLib matchPtrCount $db $matchRef]
set matchIsAlive [$dbLib matchIsAlive $db $matchRef]
lappend dot "<$matchRef> \[label=\"$matchRef (alive? $matchIsAlive) ($matchPtrCount)\"\];"
foreach childStatementRef [$dbLib childStatements $db $matchRef] {
lappend dot "<$matchRef> -> <$childStatementRef>;"
}
$dbLib matchRel $db $match
}
return "digraph { rankdir=LR; [join $dot "\n"] }"
}}} {dbLib <C:cfileqnmfGT>} {}}}}}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m513:0 (s817:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/block-stats.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m519:0 (s828:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/setup.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m520:0 (s826:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/textures.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m521:0 (s827:0 s831:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/program.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m528:0 (s834:0 s837:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/holds.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m532:0 (s841:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/program.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m536:0 (s851:0 s855:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m539:0 (s850:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/holds.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m540:0 (s854:0 s858:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/threads.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m545:0 (s863:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/db-lib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m547:0 (s869:0 s870:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/web.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m551:0 (s868:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/threads.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m552:0 (s871:0 s873:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/quads.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m560:0 (s882:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/web.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m561:0 (s883:0 s884:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/statements.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m562:0 (s885:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/quads.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m567:0 (s889:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/statements.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m571:0 (s894:0 s895:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m574:0 (s899:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/keyboards.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m580:0 (s908:0 s909:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m582:0 (s910:0 s912:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/page.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m587:0 (s918:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/trie-graph.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m588:0 (s919:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/page.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m594:0 (s925:0 s926:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m597:0 (s930:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/atomicallys.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m600:0 (s934:0 s935:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/new.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m603:0 (s939:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/new.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m608:0 (s945:0 s946:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/log.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m611:0 (s950:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/log.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m616:0 (s956:0 s957:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m619:0 (s961:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/camera-frame.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m622:0 (s965:0 s966:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m625:0 (s970:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/apriltag-frame.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m628:0 (s974:0 s975:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/report.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m631:0 (s979:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/report.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m634:0 (s983:0 s984:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m637:0 (s988:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/printed-programs.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m642:0 (s994:0 s995:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/index.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m645:0 (s999:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/index.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m650:0 (s1005:0 s1006:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/camera.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m653:0 (s1010:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/web/camera.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m658:0 (s1016:0 s1017:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m661:0 (s1021:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibration-board.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m664:0 (s1026:0 s1027:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m667:0 (s1031:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/load-calibration.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/somebody/ claims the default program (
[ m955:0 () ]
)builtin-programs/collect.folk claims the collected results for {/somebody/ claims the default program geometry is /geom/} are {{somebody <unknown> geom {tagSize 30mm left 151mm right 30mm top 30mm bottom 79mm}}}
builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camer (
[ m923:0 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camera /cam/ to display /disp/ is /anything/} are {{cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 disp monitor}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m683:0 (s1054:0 s1055:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m686:0 (s1059:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate-page.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m689:0 (s1063:0 s1064:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m692:0 (s1068:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/model.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m695:0 (s1072:0 s1073:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m698:0 (s1077:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/draw-model.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m701:0 (s1081:0 s1082:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m704:0 (s1086:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/refine.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m707:0 (s1090:0 s1091:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m710:0 (s1095:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/enumerate.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m713:0 (s1098:0 s1099:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m716:0 (s1103:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/matlib.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m719:0 (s1107:0 s1108:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m722:0 (s1112:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/calibrate/calibrate.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m726:0 (s1119:0 s1120:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m729:0 (s1124:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/pipelines.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m732:0 (s1128:0 s1129:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m735:0 (s1133:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/gpu.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m739:0 (s1139:0 s1140:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m742:0 (s1144:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/textures.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m746:0 (s1149:0 s1150:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m749:0 (s1154:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/draw.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m752:0 (s1158:0 s1159:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m755:0 (s1163:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/toy-shader.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m760:0 (s1169:0 s1170:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m763:0 (s1174:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/canvases.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m766:0 (s1178:0 s1179:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m769:0 (s1183:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/vma.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m773:0 (s1189:0 s1190:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m776:0 (s1194:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/camera/rpi.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m779:0 (s1198:0 s1199:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/decorations/label.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m782:0 (s1203:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/decorations/label.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m785:0 (s1208:0 s1209:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m788:0 (s1213:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/decorations/outline.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m791:0 (s1217:0 s1218:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m794:0 (s1222:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/draw-editor.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m797:0 (s1226:0 s1227:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m800:0 (s1231:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/editor-utils.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m804:0 (s1236:0 s1237:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/editor.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m807:0 (s1241:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/editor.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m810:0 (s1246:0 s1247:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m813:0 (s1251:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/editor/print-editor.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m816:0 (s1256:0 s1257:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m819:0 (s1261:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/save-programs.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m822:0 (s1265:0 s1266:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/saving.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m825:0 (s1270:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/saving.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m833:0 (s1285:0 s1286:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m836:0 (s1290:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/migrate.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m843:0 (s1298:0 s1299:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m846:0 (s1303:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/saving/save-holds.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m851:0 (s1309:0 s1310:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m854:0 (s1314:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/gpu/gpu-fns.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m857:0 (s1320:0 s1321:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/shapes/region.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m860:0 (s1325:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/shapes/region.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m863:0 (s1331:0 s1332:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display/arc.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m866:0 (s1336:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display/arc.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m869:0 (s1341:0 s1342:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display/curve.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m872:0 (s1346:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/display/curve.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m875:0 (s1354:0 s1355:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m878:0 (s1359:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/trocr.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m881:0 (s1364:0 s1365:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m884:0 (s1369:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/sam2.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m887:0 (s1374:0 s1375:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m890:0 (s1379:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/craft.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m893:0 (s1384:0 s1385:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs (
[ m896:0 (s1389:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program builtin-programs/recognition/contours.folk is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes to calibrate camera /any (
[ m1028:0 (s1807:0) ]
[ m1032:0 (s1812:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes to calibrate camera /any/ to display /any/ /...etc/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camer (
[ m1065:0 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camera /camera/ to display /display/ is /anything/} are {{camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 display monitor}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes folk-sva uses display gl (
[ m1099:0 (s3341:0 s3342:0 s3343:0) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes folk-sva uses display glfw with /...any/} are {}
builtin-programs/collect.folk claims the collected results for {the changer from space /sourceSpace/ (
[ m1404:0 (s2268:0) ]
)builtin-programs/collect.folk claims the collected results for {the changer from space /sourceSpace/ to space /targetSpace/ is /changer/} are {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}
builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camer (
[ m4499:0 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is /anything/} are {{}}
builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camer (
[ m23661:0 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ claims a calibration from camera /cam/ to display monitor is /anything/} are {{cam /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 63 does not run} (
[ m39946:404 () ]
[ m3373:1022 (s32225:1215 s32226:1215) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 63 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 63 is replaced w (
[ m39949:404 () ]
[ m3377:1022 (s32229:1205) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 63 is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipelin ()builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {62 canvas} with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 62 does not run} (
[ m47955:639 (s15562:766 s15565:766) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 62 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 62 is replaced w (
[ m48158:643 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 62 is replaced with /...anything/} are {{anything {code {Claim the animation toy's frame count is 6
Claim the animation toy's fps is 4
} editedTime 1778278213}}}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 82 has geometry (
[ m6667:985 (s53216:1172 s53218:1174 s38504:827 s53221:1172) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 82 has geometry /geom/} are {{geom {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 11 does not run} (
[ m33932:727 (s14341:866 s14344:854) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 11 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 11 is replaced w (
[ m33941:727 (s14352:864) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 11 is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipelin ()builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {11 canvas} with /...options/} are {{wisher builtin-programs/draw/image.folk name image options {arguments {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} 18 {0 0} {0.100666666667 0} {0.100666666667 0.100666666667} {0 0.100666666667}}}}}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 11 has geometry (
[ m25660:915 (s2792:1088 s2793:1088 s14279:866 s2796:1088) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 11 has geometry /geom/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is labelled /text (
[ m25761:915 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 54 does not run} (
[ m6514:983 (s53029:1175 s53031:1175) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 54 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 54 is replaced w (
[ m6589:990 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 54 is replaced with /...anything/} are {{anything {code set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 15ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n editedTime 1778274042}}}
builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipelin ()builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {54 canvas} with /...options/} are {{wisher builtin-programs/draw/line.folk name line options {instances {{{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0 0} {0.211 0} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.211 0} {0.211 0.139} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.211 0.139} {0 0.139} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0 0.139} {0 0} 0.01 {0.0 0.501960784314 0.0 1.0}}} layer 0}} {wisher builtin-programs/draw/text.folk name glyph options {instances {{{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.6825 0.2925 0.7575 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0799425 0.0846875} {0.0893175 0.0846875} {0.0893175 0.100313} {0.0799425 0.100313} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.0025 0.2925 0.0825 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.09053 0.0846075} {0.10053 0.0846075} {0.10053 0.100232} {0.09053 0.100232} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.1975 0.5525 0.2825 0.6825} {1.0 1.0 1.0 1.0} {1024 1024} {0.100627 0.084375} {0.111253 0.084375} {0.111253 0.100625} {0.100627 0.100625} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.4275 0.0625 0.4575 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.112365 0.0886125} {0.116115 0.0886125} {0.116115 0.100488} {0.112365 0.100488} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.8375 0.4225 0.9325 0.5475} {1.0 1.0 1.0 1.0} {1024 1024} {0.120482 0.0845775} {0.132357 0.0845775} {0.132357 0.100203} {0.120482 0.100203} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.6825 0.2925 0.7575 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0424925 0.104687} {0.0518675 0.104687} {0.0518675 0.120312} {0.0424925 0.120312} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.9425 0.3225 0.9975 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0526425 0.108462} {0.0595175 0.108462} {0.0595175 0.120337} {0.0526425 0.120337} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.7225 0.1925 0.7975 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.0588125 0.108562} {0.0681875 0.108562} {0.0681875 0.120437} {0.0588125 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.8025 0.1925 0.9225 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.06943 0.108443} {0.08443 0.108443} {0.08443 0.120317} {0.06943 0.120317} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.2525 0.0625 0.3325 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.08505 0.108562} {0.09505 0.108562} {0.09505 0.120437} {0.08505 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.9275 0.1925 0.9975 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.100765 0.108562} {0.109515 0.108562} {0.109515 0.120437} {0.100765 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.3375 0.0625 0.4225 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.109537 0.108562} {0.120162 0.108562} {0.120162 0.120437} {0.109537 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.1725 0.0625 0.2475 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.120942 0.108682} {0.130317 0.108682} {0.130317 0.120557} {0.120942 0.120557} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.0025 0.0625 0.0775 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.131852 0.108443} {0.141227 0.108443} {0.141227 0.120317} {0.131852 0.120317} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.5225 0.1725 0.5875 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.141257 0.106212} {0.149382 0.106212} {0.149382 0.120587} {0.141257 0.120587} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.4275 0.0625 0.4575 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.149815 0.108612} {0.153565 0.108612} {0.153565 0.120487} {0.149815 0.120487} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.2475 0.7025 0.3275 0.8325} {1.0 1.0 1.0 1.0} {1024 1024} {0.15895 0.104375} {0.16895 0.104375} {0.16895 0.120625} {0.15895 0.120625} 3}} layer 0}}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 82 does not run} (
[ m6723:990 (s53280:1175 s53284:1175) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 82 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 82 is replaced w (
[ m6732:978 (s53295:1175) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 82 is replaced with /...anything/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 62 has geometry (
[ m3060:1024 (s31841:1214 s31842:1146 s55973:746 s31844:1157) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 62 has geometry /geom/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is labelled /text (
[ m3092:1024 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is left-m (
[ m44363:1037 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is right- (
[ m44369:1037 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is footno (
[ m44374:1032 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is titled (
[ m44382:1038 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 63 has geometry (
[ m44641:1039 (s51838:1229 s51840:1232 s12973:51 s51843:1233) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 63 has geometry /geom/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is labelled /text (
[ m44688:1038 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is left-margined (
[ m21687:1049 () ]
[ m16190:1051 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is right-margined (
[ m21698:1048 () ]
[ m16196:1053 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is footnoted /tex (
[ m21705:1049 () ]
[ m16201:1052 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is titled /text/} (
[ m21712:1049 () ]
[ m16205:1052 (s40302:1249) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 62 is titled /text/} are {{text {(edited Fri, 08 May 2026, 10:10 PM)}}}
builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipelin ()builtin-programs/collect.folk claims the collected results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {83 canvas} with /...options/} are {{wisher builtin-programs/draw/line.folk name line options {instances {{{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0} {0.2159 0} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0} {0.2159 0.1397} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0.1397} {0 0.1397} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0.1397} {0 0} 0.01 {1.0 1.0 1.0 1.0}}} layer 0}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is left-margined (
[ m16461:1048 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is titled /text/} (
[ m16469:1052 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is right-margined (
[ m16470:1049 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is footnoted /tex (
[ m16478:1053 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 63 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {folk-sva has display /display/ with / (
[ m61805:1036 (s49334:1249) ]
)builtin-programs/collect.folk claims the collected results for {folk-sva has display /display/ with /...opts/} are {{display monitor opts {info {name {monitor} physicalDimensions {1016 571} physicalResolution {3840 2160} modes {{visibleRegion {3840 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 59940} {visibleRegion {4096 2160} refreshRate 50000} {visibleRegion {4096 2160} refreshRate 30000} {visibleRegion {4096 2160} refreshRate 29970} {visibleRegion {4096 2160} refreshRate 25000} {visibleRegion {4096 2160} refreshRate 24000} {visibleRegion {4096 2160} refreshRate 23976} {visibleRegion {3840 2160} refreshRate 59940} {visibleRegion {3840 2160} refreshRate 50000} {visibleRegion {3840 2160} refreshRate 30000} {visibleRegion {3840 2160} refreshRate 29970} {visibleRegion {3840 2160} refreshRate 25000} {visibleRegion {3840 2160} refreshRate 24000} {visibleRegion {3840 2160} refreshRate 23976} {visibleRegion {2288 1430} refreshRate 61015} {visibleRegion {1920 1200} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 240000} {visibleRegion {1920 1080} refreshRate 120000} {visibleRegion {1920 1080} refreshRate 119880} {visibleRegion {1920 1080} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 59940} {visibleRegion {1920 1080} refreshRate 50000} {visibleRegion {1920 1080} refreshRate 30000} {visibleRegion {1920 1080} refreshRate 29970} {visibleRegion {1920 1080} refreshRate 24000} {visibleRegion {1920 1080} refreshRate 23976} {visibleRegion {1600 1200} refreshRate 60000} {visibleRegion {1680 1050} refreshRate 60000} {visibleRegion {1280 1024} refreshRate 60000} {visibleRegion {1440 900} refreshRate 60000} {visibleRegion {1280 800} refreshRate 60000} {visibleRegion {1280 720} refreshRate 60000} {visibleRegion {1280 720} refreshRate 59940} {visibleRegion {1280 720} refreshRate 50000} {visibleRegion {1024 768} refreshRate 60000} {visibleRegion {800 600} refreshRate 60000} {visibleRegion {720 576} refreshRate 50000} {visibleRegion {720 480} refreshRate 60000} {visibleRegion {720 480} refreshRate 59940} {visibleRegion {640 480} refreshRate 60000} {visibleRegion {640 480} refreshRate 59940}}}}}}
builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ (
[ m61830:1055 () ]
[ m61839:1041 () ]
)builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are /results/} are {{results {{usingOpts {width 4096 height 2160 refreshRate 60000}} {usingOpts {width 1920 height 1200 refreshRate 60000}}}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses displa (
[ m61828:1042 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses display monitor with /...usingOpts/} are {{usingOpts {width 4096 height 2160 refreshRate 60000}} {usingOpts {width 1920 height 1200 refreshRate 60000}}}
builtin-programs/collect.folk claims the collected results for {folk-sva has camera /camera/ with /.. (
[ m61861:1044 (s49409:1250 s49418:1249) ]
)builtin-programs/collect.folk claims the collected results for {folk-sva has camera /camera/ with /...opts/} are {{camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {{fourcc {MJPG} description {Motion-JPEG} resolutions {{width 640 height 480 framerates {60.0 30.0}} {width 1600 height 896 framerates {60.0 30.0}} {width 1280 height 720 framerates {60.0 30.0}} {width 1024 height 768 framerates {60.0 30.0}} {width 1024 height 576 framerates {60.0 30.0}} {width 960 height 544 framerates {60.0 30.0}} {width 864 height 480 framerates {60.0 30.0}} {width 848 height 480 framerates {60.0 30.0}} {width 800 height 448 framerates {60.0 30.0}} {width 640 height 360 framerates {60.0 30.0}} {width 352 height 288 framerates {60.0 30.0}} {width 320 height 240 framerates {60.0 30.0}} {width 1920 height 1080 framerates {60.0 30.0}}}} {fourcc {YUYV} description {YUYV 4:2:2} resolutions {{width 640 height 480 framerates {30.0}} {width 1600 height 896 framerates {5.0}} {width 1280 height 720 framerates {10.0 5.0}} {width 1024 height 768 framerates {10.0 5.0}} {width 1024 height 576 framerates {10.0 5.0}} {width 960 height 544 framerates {10.0 5.0}} {width 864 height 480 framerates {10.0 5.0}} {width 848 height 480 framerates {10.0 5.0}} {width 800 height 448 framerates {10.0 5.0}} {width 640 height 360 framerates {30.0}} {width 352 height 288 framerates {30.0}} {width 320 height 240 framerates {30.0}} {width 1920 height 1080 framerates {5.0}}}}}}} {camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 opts {card {NexiGo HD Webcam: NexiGo HD Web} formats {}}}}
builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ (
[ m61894:1048 () ]
[ m61898:1048 () ]
)builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are /results/} are {{results {}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera (
[ m61893:969 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with /...usingOpts/} are {}
builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ (
[ m61919:1053 () ]
[ m61923:1053 () ]
)builtin-programs/collect.folk claims the collected results for {the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are /results/} are {{results {{usingOpts {width 1920 height 1080 framerate 60.0}}}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera (
[ m61914:1055 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with /...usingOpts/} are {{usingOpts {width 1920 height 1080 framerate 60.0}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses displa (
[ m61935:1053 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses display /display/ with /...opts/} are {{display monitor opts {width 4096 height 2160 refreshRate 60000}} {display monitor opts {width 1920 height 1200 refreshRate 60000}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera (
[ m62007:1053 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes folk-sva uses camera /camera/ with /...opts/} are {{camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 opts {width 1920 height 1080 framerate 60.0}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is titled /text/} (
[ m17871:1058 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is left-margined (
[ m17878:1057 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is right-margined (
[ m17886:1058 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is footnoted /tex (
[ m17888:1058 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 82 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is left-margined (
[ m23208:1061 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is right-margined (
[ m23218:1062 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is footnoted /tex (
[ m23225:1061 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is titled /text/} (
[ m23229:1059 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 11 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 54 has geometry (
[ m23350:1059 (s14677:1260 s14678:1260 s53065:1170 s14680:1260) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 54 has geometry /geom/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is labell (
[ m23386:1040 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is labell (
[ m23391:1062 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is labell (
[ m23401:1040 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is labell (
[ m23407:1062 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is labell (
[ m23413:1039 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is labell (
[ m23419:1062 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is labell (
[ m23433:1062 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-display is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is labelled /text ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is labelled /text/ with /...options/} are {{text {FPS: 4
Frame count: 6} options {font PTSans-Regular}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-6 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is titled /text/} ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is titled /text/} are {{text {(edited Fri, 08 May 2026, 09:00 PM)}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is left-margined ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is right-margined ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is footnoted /tex ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 83 has geometry (
[ m47715:1056 (s64469:1262 s64472:1262 s59987:1247 s64481:1262) ]
)builtin-programs/collect.folk claims the collected results for {/someone/ claims tag 83 has geometry /geom/} are {{geom {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}}}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 83 does not run} (
[ m47718:1064 (s64473:1262 s64479:1262) ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 83 does not run} are {}
builtin-programs/collect.folk claims the collected results for {/any/ wishes program 83 is replaced w (
[ m47776:1061 () ]
)builtin-programs/collect.folk claims the collected results for {/any/ wishes program 83 is replaced with /...anything/} are {{anything {code {Claim $this is a viewport
Wish $this is outlined white} editedTime 1781548209}}}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is labelled /text (
[ m47787:1061 () ]
)builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is labelled /text/ with /...options/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-5 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-1 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-4 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-2 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is left-m ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is right- ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is footno ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is titled ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 54-frame-3 is titled /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is left-margined ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is left-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is right-margined ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is right-margined /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is footnoted /tex ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is footnoted /text/} are {}
builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is titled /text/} ()builtin-programs/collect.folk claims the collected results for {/someone/ wishes 83 is titled /text/} are {{text {(edited Mon, 15 Jun 2026, 06:30 PM)}}}
subscribe keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ()subscribe keyboard /k/ claims key Meta_Escape is down with /...options/ {
puts "==== Folk restarting ... ===="
exec sudo systemctl restart folk
} with environment {{this builtin-programs/keyboard-shortcuts.folk} {} {}}
subscribe keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. == ()subscribe keyboard /k/ claims key Console_1 is down with /...options/ {
puts "==== Stopping Folk. ===="
puts "===="
puts " Run `make sync-restart` on your laptop or SSH into [info hostname] to restart Folk ===="
puts "===="
exec sudo systemctl stop folk
Exit! 0
} with environment {{this builtin-programs/keyboard-shortcuts.folk} {} {}}
subscribe keyboard /keyboard/ claims key Control_b is down with /...options/ {
Notify: print code ()subscribe keyboard /keyboard/ claims key Control_b is down with /...options/ {
Notify: print code "# blank"
} with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
subscribe print pdf /pdfPath/ with /...options/ \n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set ()subscribe print pdf /pdfPath/ with /...options/ \n\ \ \ \ if\ \{!\[info\ exists\ options\]\}\ \{\ set\ options\ \{\}\ \}\n\n\ \ \ \ set\ args\ \[list\]\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ printer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ printer\ /./\ is\ the\ default\ printer\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ printer\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -P\ \$options(printer)\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ options\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\]\n\ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\}\n\ \ \ \ \}\n\ \ \ \ if\ \{\[dict\ exists\ \$options\ format\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ args\ -o\ media=\$options(format)\n\ \ \ \ \}\n\n\ \ \ \ exec\ lpr\ \{*\}\$args\ \$pdfPath\n with environment {{this builtin-programs/print/print.folk} {} {}}
subscribe print program from editor /editor/ {
set options [editorToPrintOptions $editor]
Not ()subscribe print program from editor /editor/ {
set options [editorToPrintOptions $editor]
Notify: print a new program with {*}$options
} with environment {{this builtin-programs/editor/print-editor.folk} {} {^editorToPrintOptions {editor \n\ \ \ \ Expect!\ editor\ \$editor\ has\ selected\ program\ /program/\n\ \ \ \ Expect!\ editor\ buffer\ for\ \$program\ is\ /code/\n\n\ \ \ \ Expect!\ editor\ \$editor\ on\ program\ \$program\ has\ font\ options\ with\ /...fontOptions/\n\ \ \ \ set\ textScale\ \$fontOptions(scale)\n\ \ \ \ Expect!\ editor\ \$editor\ has\ margin\ /margin/\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ return\ \[dict\ merge\ \$fmt\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n {builtin-programs/editor/print-editor.folk 1}}}}
subscribe print program /id/ on receipt printer /printer/ with code /code/ {
printProgram $pr ()subscribe print program /id/ on receipt printer /printer/ with code /code/ {
printProgram $printer $id $code
} with environment {{this builtin-programs/esc-pos.folk} {} {} {printLib <C:cfileDzXJHE>} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^raw {number {
return [format "%c" $number]
} {builtin-programs/esc-pos.folk 61}} ^tag {{id {scale 12}} {
set tagBits [scaledAprilTag $id $scale]
set width [expr {10 * $scale}]
set xL [expr {$width / 8}] ;# width in bytes (low byte)
set yL [expr {$width % 256}] ;# height in lines (low byte)
set yH [expr {$width / 256}] ;# height in lines (high byte)
return "\x1dv0\x03[raw $xL]\x00[raw $yL][raw $yH][binary format B* [join $tagBits ""]]"
} {builtin-programs/esc-pos.folk 81}} ^init {{} {
return "\x1b\x40"
} {builtin-programs/esc-pos.folk 57}} ^cut {{} {
return "\x1dV\x0"
} {builtin-programs/esc-pos.folk 49}} ^scaledAprilTag {{id scale} {
set tagImage [$printLib tagImageForId $id]
set tagBits [list]
for {set y 0} {$y < 10} {incr y} {
for {set i 0 } {$i < $scale} {incr i} {
for {set x 0} {$x < 10} {incr x} {
set j [expr {$y * [$imageLib Image_bytesPerRow $tagImage] + $x}]
set bit [expr {[$imageLib Image_data $tagImage $j] != 255}]
lappend tagBits {*}[lrepeat $scale $bit]
}
}
}
return $tagBits
} {builtin-programs/esc-pos.folk 65}} ^render {template {
set trimmed [lmap line [split $template "\n"] { string trim $line }]
set singleLine [join $trimmed ""]
return [uplevel [list subst $singleLine]]
} {builtin-programs/esc-pos.folk 30}} ^writeMetaFile {{printer id} {
Expect! $printer has tag geometry /geometry/
set metaFile [open "$saveDir/$id.meta.folk" w]
puts $metaFile [subst {Claim tag \$this has geometry {$geometry}}]
close $metaFile
} {builtin-programs/esc-pos.folk 42}} ^feed {n {
return [format "\x1b\x64%c" $n]
} {builtin-programs/esc-pos.folk 53}} ^printProgram {{printer id code} {
if {[file exists "$saveDir/$id.folk"]} {
error "Program $id already exists on disk. Aborting print."
}
writeFolkFile $id $code
writeMetaFile $printer $id
Expect! $printer is at /address/
set printerSocket [socket stream ${address}:9100]
fconfigure $printerSocket -translation binary -buffering none
set template {
[init]
[tag $id]
[feed 1]
$id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])
[feed 2]
$code
[feed 3]
[cut]
}
puts -nonewline $printerSocket [render $template]
close $printerSocket
} {builtin-programs/esc-pos.folk 5}} ^writeFolkFile {{id code} {
set folkFile [open "$saveDir/$id.folk" w]
puts $folkFile $code
close $folkFile
} {builtin-programs/esc-pos.folk 36}}}}
subscribe print program /id/ with /...options/ \n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\ ()subscribe print program /id/ with /...options/ \n\ \ \ \ set\ code\ \[dict\ get\ \$options\ code\]\n\n\ \ \ \ ForEach!\ printer\ /printer/\ is\ a\ receipt\ printer\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ printer\ /printer/\ is\ the\ default\ printer\ \{\n\ \ \ \ \ \ \ \ Notify:\ print\ program\ \$id\ on\ receipt\ printer\ \$printer\ with\ code\ \$code\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ calibScaleResults\ \[Query!\ the\ calibrated\ print\ scale\ is\ /scale/\]\n\ \ \ \ if\ \{\[llength\ \$calibScaleResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ calibScale\ \[dict\ get\ \[lindex\ \$calibScaleResults\ 0\]\ scale\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ tagInnerSideLength\ \[expr\ \{70.0\ /\ \$calibScale\}\]\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintScale\ \$calibScale\n\ \ \ \ \}\n\n\ \ \ \ set\ calibTranslationResults\ \[Query!\ the\ calibrated\ print\ translation\ is\ /translation/\]\n\ \ \ \ if\ \{\[llength\ \$calibTranslationResults\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ dict\ set\ options\ calibratedPrintTranslation\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \[lindex\ \$calibTranslationResults\ 0\]\ translation\]\n\ \ \ \ \}\n\n\ \ \ \ dict\ set\ options\ tagInset\ 16\n\n\ \ \ \ set\ printedMargins\ \{\}\n\ \ \ \ set\ ps\ \[codeToPostScript\ \$id\ \$code\ \$options\ printedMargins\]\n\n\ \ \ \ #\ save\ code\ and\ ps\ to\ disk\n\ \ \ \ if\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Program\ \$id\ already\ exists\ on\ disk.\ Aborting\ print.\"\n\ \ \ \ \}\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.folk\"\ w\]\;\ puts\ \$fp\ \$code\;\ close\ \$fp\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.ps\"\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ exec\ ps2pdf\ -dPDFSETTINGS=/prepress\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ \$saveDir/\$id.ps\ \$saveDir/\$id.pdf\n\n\ \ \ \ #\ Write\ geometry\ to\ meta.folk\ so\ the\ camera\ system\ can\ interpret\n\ \ \ \ #\ this\ program's\ quad\ and\ map\ (line,\ col)\ ->\ physical\ position.\n\ \ \ \ #\ All\ opts\ are\ in\ calibrated\ points\;\ 1\ calibrated\ pt\ =\ 25.4/72\ mm.\n\ \ \ \ set\ ptmm\ \[expr\ \{25.4\ /\ 72.0\}\]\n\ \ \ \ lassign\ \[dict\ get\ \$options\ pageSize\]\ PageWidth\ PageHeight\n\ \ \ \ set\ tagInn\ \[dict\ get\ \$options\ tagInnerSideLength\]\n\ \ \ \ set\ tagOut\ \[expr\ \{\$tagInn\ *\ 10.0\ /\ 6\}\]\n\ \ \ \ set\ lh\ \[dict\ get\ \$options\ lineHeight\]\n\ \ \ \ set\ adv\ \[dict\ get\ \$options\ advance\]\n\n\ \ \ \ set\ tagInset\ \[dict\ get\ \$options\ tagInset\]\n\ \ \ \ set\ border\ \[expr\ \{(\$tagOut\ -\ \$tagInn)\ /\ 2.0\}\]\n\n\ \ \ \ #\ Geometry\ should\ reflect\ where\ the\ tag\ actually\ lands\ on\ the\n\ \ \ \ #\ paper,\ so\ use\ printedMargins.\n\ \ \ \ set\ gLeft\ \ \ \[expr\ \{(\$PageWidth\ -\ \$tagOut\ -\ \$printedMargins(right)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gRight\ \ \[expr\ \{(\$printedMargins(right)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gTop\ \ \ \ \[expr\ \{(\$printedMargins(top)\ +\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\ \ \ \ set\ gBottom\ \[expr\ \{(\$PageHeight\ -\ \$tagOut\ -\ \$printedMargins(top)\ -\ \$tagInset\ +\ \$border)\ *\ \$ptmm\}\]\n\n\ \ \ \ #\ If\ the\ first\ page\ is\ sparse\ enough,\ assume\ the\ user\ will\ fold\ the\n\ \ \ \ #\ page\ in\ half\ vertically\ and\ shrink\ the\ reported\ bottom\ geometry.\n\ \ \ \ set\ numLines\ \[llength\ \[split\ \$code\ \"\\n\"\]\]\n\ \ \ \ set\ maxLines\ \[expr\ \{int((\$PageHeight\ -\ \$printedMargins(top)\ -\ \$printedMargins(bottom))\ /\ \$lh)\}\]\n\ \ \ \ set\ firstPageLines\ \[expr\ \{\$numLines\ <\ \$maxLines\ ?\ \$numLines\ :\ \$maxLines\}\]\n\ \ \ \ if\ \{\$firstPageLines\ <\ \$maxLines\ /\ 2.0\}\ \{\n\ \ \ \ \ \ \ \ set\ tagSize\ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\n\ \ \ \ \ \ \ \ set\ pageHeightMm\ \[expr\ \{\$tagSize\ +\ \$gTop\ +\ \$gBottom\}\]\n\ \ \ \ \ \ \ \ set\ gBottom\ \[expr\ \{\$gBottom\ -\ \$pageHeightMm\ /\ 2.0\}\]\n\ \ \ \ \}\n\n\ \ \ \ set\ geomStr\ \[format\ \\\n\ \ \ \ \ \ \ \ \{tagSize\ %.4gmm\ left\ %.4gmm\ right\ %.4gmm\ top\ %.4gmm\ bottom\ %.4gmm\ lineHeight\ %.4gmm\ advance\ %.4gmm\ marginTop\ %.4gmm\ marginRight\ %.4gmm\ marginBottom\ %.4gmm\ marginLeft\ %.4gmm\}\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$tagInn\ *\ \$ptmm\}\]\ \$gLeft\ \$gRight\ \$gTop\ \$gBottom\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$lh\ *\ \$ptmm\}\]\ \[expr\ \{\$adv\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(top)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(right)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(bottom)\ *\ \$ptmm\}\]\ \\\n\ \ \ \ \ \ \ \ \[expr\ \{\$printedMargins(left)\ *\ \$ptmm\}\]\]\n\n\ \ \ \ set\ fp\ \[open\ \"\$saveDir/\$id.meta.folk\"\ w\]\n\ \ \ \ puts\ \$fp\ \"Claim\ tag\ \\\$this\ has\ geometry\ \\\{\$geomStr\\\}\"\n\ \ \ \ close\ \$fp\n\n\ \ \ \ puts\ \"Printing\ program\ \$id\ on\ \$::thisNode\"\n\ \ \ \ Notify:\ print\ pdf\ \$saveDir/\$id.pdf\ with\ \{*\}\$options\n with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} ^nextId {{} \n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n {builtin-programs/print/print.folk 188}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}
subscribe print code /code/ \n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ form ()subscribe print code /code/ \n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ set\ fmt\ \$formats(\$formatName)\n\n\ \ \ \ set\ mToPt\ 2834.646\n\ \ \ \ set\ textScale\ 0.003\n\ \ \ \ set\ margin\ \{0.01\ 0.005\ 0.005\ 0.01\}\n\ \ \ \ set\ options\ \[dict\ merge\ \$fmt\ \[dict\ create\ \\\n\ \ \ \ \ \ \ \ code\ \$code\ \\\n\ \ \ \ \ \ \ \ lineHeight\ \[*\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ advance\ \[*\ 0.5859375\ \$textScale\ \$mToPt\]\ \\\n\ \ \ \ \ \ \ \ margin\ \[lmap\ x\ \$margin\ \{*\ \$x\ \$mToPt\}\]\]\]\n\ \ \ \ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\n with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} ^nextId {{} \n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n {builtin-programs/print/print.folk 188}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}
subscribe print a new program with /...options/ \n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ ()subscribe print a new program with /...options/ \n\ \ \ \ if\ \{\$::thisNode\ eq\ \"folk-beads\"\ ||\ \$::thisNode\ eq\ \"folk-convivial\"\}\ \{\n\ \ \ \ \ \ \ \ #\ HACK:\ Forward\ the\ print\ request\ to\ folk-hex.\n\ \ \ \ \ \ \ \ exec\ curl\ -X\ POST\ \"http://folk-hex.local:4273/\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -H\ \"Content-Type:\ text/plain\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -d\ \[list\ Notify:\ print\ a\ new\ program\ with\ \{*\}\$options\]\;\n\ \ \ \ \ \ \ \ return\n\ \ \ \ \}\n\n\ \ \ \ set\ id\ \[nextId\]\n\ \ \ \ Notify:\ print\ program\ \$id\ with\ \{*\}\$options\n with environment {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} ^nextId {{} \n\ \ \ \ set\ idResults\ \[Query!\ the\ next\ program\ id\ is\ /id/\]\n\ \ \ \ if\ \{\[llength\ \$idResults\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ id\ 0\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \[lindex\ \$idResults\ 0\]\ id\]\n\ \ \ \ \}\n\n\ \ \ \ while\ \{\[file\ exists\ \"\$saveDir/\$id.folk\"\]\}\ \{\n\ \ \ \ \ \ \ \ incr\ id\n\ \ \ \ \}\n\n\ \ \ \ #\ HACK:\ using\ old\ path\ for\ backward\ compatibility.\n\ \ \ \ Hold!\ -save\ -on\ builtin-programs/print.folk\ -key\ next-id\ \\\n\ \ \ \ \ \ \ \ the\ next\ program\ id\ is\ \$id\n\n\ \ \ \ set\ id\n {builtin-programs/print/print.folk 188}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}
subscribe save code on editor /editor/ \n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ ()subscribe save code on editor /editor/ \n\ \ \ \ ForEach!\ editor\ \$editor\ has\ selected\ program\ /program/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ editor\ buffer\ for\ /program/\ is\ /programCode/\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/programs.folk\ -key\ new-code-for:\$program\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ program\ \$program\ is\ replaced\ with\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ code\ \$programCode\ editedTime\ \[clock\ seconds\]\n\n\ \ \ \ \ \ \ \ set\ programBase\ \[regsub\ \{\\.folk\$\}\ \$program\ \"\"\]\n\ \ \ \ \ \ \ \ set\ editedPath\ \"\$programDir/\[set\ programBase\].folk.edited\"\n\ \ \ \ \ \ \ \ file\ mkdir\ \[file\ dirname\ \$editedPath\]\n\ \ \ \ \ \ \ \ set\ fp\ \[open\ \$editedPath\ w\]\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$programCode\n\ \ \ \ \ \ \ \ close\ \$fp\n\n\ \ \ \ \ \ \ \ #\ Give\ the\ user\ some\ feedback\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$editor\ is\ labelled\ \"Saved!\"\n\ \ \ \ \ \ \ \ sleep\ 0.25\n\ \ \ \ \ \ \ \ Hold!\ -key\ saved-alert:\$editor\ \{\}\n\ \ \ \ \}\n with environment {{this builtin-programs/editor/editor.folk} {} {} {programDir /home/folk/folk-data/program} {} {utils <library:/tmp/editorUtilsLib_YaXWyk.tcl>} {defaults { textScale 0.01 }}}
subscribe save hold on /on/ with key /key/ clause /clause/ \n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ ()subscribe save hold on /on/ with key /key/ clause /clause/ \n\ \ \ \ \ \ \ \ set\ canonical\ \$on\n\ \ \ \ \ \ \ \ set\ tclEscaped\ \[list\ \$on\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\"\n\n\ \ \ \ \ \ \ \ #\ does\ it\ match\ builtin-programs/**/*.folk?\ If\ so,\n\ \ \ \ \ \ \ \ #\ chop\ off\ builtin-programs/\n\ \ \ \ \ \ \ \ if\ \{!\[regexp\ \{^builtin-programs/(.*\\.folk)\}\ \$canonical\ ->\ escapedFilename\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedFilename\ \$canonical\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ replace\ all\ /\ with\ __\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \[regsub\ -all\ --\ /\ \$escapedFilename\ __\]\n\ \ \ \ \ \ \ \ set\ escapedFilename\ \"\$holdDirectory/\$escapedFilename\"\n\n\ \ \ \ \ \ \ \ \$savedHoldsLib\ saveHold\ \$canonical\ \$tclEscaped\ \$escapedFilename\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \$key\ \$clause\n\ \ \ \ with environment {{this builtin-programs/saving/save-holds.folk} {} {savedHoldsLib <C:cfilecAUX4H> cc ::<reference.<C______>.00000000000000000006>} {holdDirectory /home/folk/folk-data/hold} {}}
builtin-programs/demos.folk claims 45000 has demo code {
Wish $this is labelled "Welcome to Folk! ()builtin-programs/demos.folk claims 45000 has demo code {
Wish $this is labelled "Welcome to Folk! This is a program"
Wish $this is outlined green
}
builtin-programs/demos.folk claims 45001 has demo code {
Wish $this is labelled "My wishes came t ()builtin-programs/demos.folk claims 45001 has demo code {
Wish $this is labelled "My wishes came true!"
Wish $this is outlined blue
}
builtin-programs/demos.folk claims 45002 has demo code {
When /actor/ is cool {
Wish $thi ()builtin-programs/demos.folk claims 45002 has demo code {
When /actor/ is cool {
Wish $this is labelled "$actor is pretty cool"
Wish $actor is outlined red
}
}
builtin-programs/demos.folk claims 45003 has demo code {
Claim $this is actor
Claim $this is ()builtin-programs/demos.folk claims 45003 has demo code {
Claim $this is actor
Claim $this is cool
}
builtin-programs/demos.folk claims 45004 has demo code {
When the clock time is /t/ {
Wis ()builtin-programs/demos.folk claims 45004 has demo code {
When the clock time is /t/ {
Wish $this is labelled $t
}
}
builtin-programs/demos.folk claims 45005 has demo code {
When the clock time is /t/ {
Wis ()builtin-programs/demos.folk claims 45005 has demo code {
When the clock time is /t/ {
Wish $this draws a circle offset [list expr {sin($t) * 50} 0]
}
}
builtin-programs/demos.folk claims 45006 has demo code {
Wish $this is outlined blue
When $th ()builtin-programs/demos.folk claims 45006 has demo code {
Wish $this is outlined blue
When $this points up at /p/ {
Wish $this is labelled "Pointing at $p"
Wish $p is labelled "and I am being pointed at"
}
}
builtin-programs/demos.folk claims 45007 has demo code {
Wish $this is outlined red
Wish $thi ()builtin-programs/demos.folk claims 45007 has demo code {
Wish $this is outlined red
Wish $this is labelled "I am a program"
}
builtin-programs/demos.folk claims 45008 has demo code {
When $this has camera slice /slice/ {
()builtin-programs/demos.folk claims 45008 has demo code {
When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
builtin-programs/terminal.folk has error {FIXME: terminal.folk not currently working.} with info {-co (
[ m286:0 (s445:0 s447:0) ]
)builtin-programs/terminal.folk has error {FIXME: terminal.folk not currently working.} with info {-code 1 -level 0 -errorinfo {evaluateBlock builtin-programs/terminal.folk 26 {error {FIXME: terminal.folk not currently working.}} evaluateBlock prelude.tcl 185:8 {apply {{this __envStack __env} #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n} builtin-programs/terminal.folk {{this builtin-programs/terminal.folk} {}} {this builtin-programs/terminal.folk __envStack {{this builtin-programs/terminal.folk} {}}}} {} {} 1 {evaluateBlock #\ Terminal\n#\n#\ Spawn\ terminals\ with\ any\ command\ (default\ \"bash\"):\n#\ \ \ Wish\ \$this\ is\ a\ terminal\n#\ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"any\ command\"\n#\n#\ Send\ keyboard\ events\ to\ the\ terminal:\n#\ \ \ Claim\ \$thing\ has\ keyboard\ input\n#\n#\ Optionally,\ draw\ the\ terminal\ on\ an\ arbitrary\ region:\n#\ \ \ Claim\ \$thing\ has\ terminal\ region\ \$region\n#\n#\n#\ Example\ program:\ Tie\ it\ all\ together\ with\ a\ simple\ vim\ editor...\n#\n#\ \ \ When\ \$this\ points\ up\ at\ /target/\ &\ /target/\ has\ program\ /anything/\ \{\n#\ \ \ \ \ Wish\ \$this\ is\ a\ terminal\ spawning\ \"vim\ ~/folk-printed-programs/\$target.folk\"\n#\ \ \ \ \ When\ \$this\ has\ region\ /r/\ \{\n#\ \ \ \ \ \ \ Claim\ \$this\ has\ terminal\ region\ \[region\ move\ \$r\ right\ 350px\]\n#\ \ \ \ \ \}\n#\ \ \ \ \ Claim\ \$this\ has\ keyboard\ input\n#\ \ \ \}\n#\n#\n\nerror\ \"FIXME:\ terminal.folk\ not\ currently\ working.\"\n\nsource\ lib/terminal.tcl\n\n#\ WIP:\ Needs\ to\ finish\ being\ fixed\ for\ folk2.\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ \{\n\ \ Wish\ \$thing\ is\ a\ terminal\ spawning\ bash\n\}\n\nWhen\ /thing/\ has\ terminal\ region\ /r/\ &\ /r/\ has\ keyboard\ input\ \{\n\ \ Claim\ \$thing\ has\ keyboard\ input\n\}\n\nWhen\ /anyone/\ wishes\ /thing/\ is\ a\ terminal\ spawning\ /cmd/\ \{\n\ \ set\ term\ \[\$terminalLib\ create\ 12\ 43\ \$cmd\]\n\ \ #\ Keep\ for\ 10\ minutes.\n\ \ Claim\ -keep\ \[expr\ \{10*60*1000\}\]ms\ \\\n\ \ \ \ -destructor\ \[list\ \$terminalLib\ destroy\ \$term\]\n\ \ \ \ \$thing\ has\ terminal\ \$term\ spawning\ \$cmd\n\n\ \ When\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ set\ body\ \{\n\ \ \ \ \ \ Wish\ region\ \$region\ is\ labelled\ \[\$terminalLib\ read\ \$term\]\n\ \ \ \ \}\n\ \ \ \ When\ \$thing\ has\ terminal\ region\ /region/\ \$body\n\ \ \ \ When\ /nobody/\ claims\ \$thing\ has\ terminal\ region\ /x/\ &\ \$thing\ has\ region\ /region/\ \$body\n\ \ \}\n\n\ \ When\ /anyone/\ claims\ \$thing\ has\ keyboard\ input\ \\\n\ \ \ \ &\ keyboard\ /anyone/\ claims\ key\ /key/\ is\ /direction/\ with\ /...options/\ \{\n\ \ \ \ if\ \{\$direction\ !=\ \"up\"\}\ \{\n\ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ printable\]\}\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ write\ \$term\ \[dict\ get\ \$options\ printable\]\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \$terminalLib\ handleKey\ \$term\ \$key\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\n\}\n {{this builtin-programs/terminal.folk} {}}}} -errorcode NONE}
builtin-programs/errors.folk wishes builtin-programs/terminal.folk is titled {FIXME: terminal.folk no ()builtin-programs/errors.folk wishes builtin-programs/terminal.folk is titled {FIXME: terminal.folk not currently working.}
builtin-programs/errors.folk wishes builtin-programs/terminal.folk is outlined white ()builtin-programs/errors.folk wishes builtin-programs/terminal.folk is outlined white
builtin-programs/errors.folk wishes builtin-programs/terminal-ui.folk is titled {can't read "::env(TE ()builtin-programs/errors.folk wishes builtin-programs/terminal-ui.folk is titled {can't read "::env(TERM)": no such element in array}
builtin-programs/errors.folk wishes builtin-programs/terminal-ui.folk is outlined white ()builtin-programs/errors.folk wishes builtin-programs/terminal-ui.folk is outlined white
builtin-programs/sprites.folk claims builtin-programs/sprites.folk has demo {
Wish $this draws spri ()builtin-programs/sprites.folk claims builtin-programs/sprites.folk has demo {
Wish $this draws sprite $path with 8 frames and 4 columns
}
builtin-programs/terminal-ui.folk has error {can't read "::env(TERM)": no such element in array} with (
[ m340:0 (s532:0 s537:0) ]
)builtin-programs/terminal-ui.folk has error {can't read "::env(TERM)": no such element in array} with info {-code 1 -level 0 -errorinfo {evaluateBlock builtin-programs/terminal-ui.folk 11 {if {$::env(TERM) eq "dumb"} {
return
}} evaluateBlock prelude.tcl 185:8 {apply {{this __envStack __env} {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
}} builtin-programs/terminal-ui.folk {{this builtin-programs/terminal-ui.folk} {}} {this builtin-programs/terminal-ui.folk __envStack {{this builtin-programs/terminal-ui.folk} {}}}} {} {} 1 {evaluateBlock {# Manage terminal UI for Folk.
$::realStdout puts "Folk Computer (pid [pid])."
set host $([string match "*.local" $::thisNode] ? $::thisNode : "$::thisNode.local")
$::realStdout puts "Web interface at: http://$host:4273/"
$::realStdout puts ""
$::realStdout flush
# Don't run the watcher process if we're not literally at a terminal
# (if we're running on systemd, for instance.)
if {$::env(TERM) eq "dumb"} {
return
}
set termRows 24
set termCols 80
catch { lassign [exec stty size] termRows termCols }
set maxLines [expr {$termRows - 4}]
# Visible length of a string (strips ANSI escape sequences).
fn visLen {s} {
regsub -all {\x1b\[[0-9;]*[a-zA-Z]} $s {} s
string length $s
}
set prevLineCount 0
set startMs [clock milliseconds]
while true {
set elapsedMs [expr {[clock milliseconds] - $startMs}]
set settled [expr {$elapsedMs > 60000}]
after [expr {$settled ? 500 : 40}]
set results [lsort -command {apply {{a b} {
string compare [dict get $a program] [dict get $b program]
}}} [Query! /program/ has program code /programCode/]]
# Build groups: dict mapping dirname -> list of {status basename}
set groups [dict create]
foreach result $results {
set program [dict get $result program]
set programCode [dict get $result programCode]
set runners [Query! when $programCode with environment [list [list this $program]]]
if {[llength $runners] != 1} { continue }
set runner [lindex $runners 0]
set incompleteCount [__statementIncompleteChildMatchesCount [dict get $runner __ref]]
set errors [Query! $program has error /err/ with info /info/]
set dir [file dirname $program]
set base [file rootname [file tail $program]]
if {[llength $errors] > 0} {
set status "\033\[31m!\033\[0m"
set coloredBase "\033\[31m$base\033\[0m"
} elseif {$incompleteCount == 0} {
set status "\033\[32m✓\033\[0m"
set coloredBase "\033\[32m$base\033\[0m"
} else {
if {$settled} {
set status "\033\[33m·\033\[0m"
} else {
set spinIdx [expr {([clock milliseconds] / 80) % 4}]
set status "\033\[33m[lindex {| / - \\} $spinIdx]\033\[0m"
}
set coloredBase "\033\[33m$base\033\[0m"
}
dict lappend groups $dir [list $status $coloredBase]
}
# Build lines, word-wrapping each group's entries to fit termCols.
set lines {}
dict for {dir members} $groups {
set prefix "$dir/ "
set indent [string repeat " " [visLen $prefix]]
set line $prefix
foreach member $members {
lassign $member status base
set word "${status} $base"
if {[visLen $line] == [visLen $prefix]} {
append line $word
} elseif {[visLen $line] + 3 + [visLen $word] > $termCols} {
lappend lines $line
set line "$indent$word"
} else {
append line " $word"
}
}
lappend lines $line
}
if {[llength $lines] > $maxLines} {
set lines [lrange $lines 0 $maxLines-1]
}
if {$prevLineCount > 0} {
$::realStdout puts -nonewline "\033\[${prevLineCount}A\r"
}
$::realStdout puts -nonewline "\033\[?7l"
foreach line $lines {
$::realStdout puts -nonewline "$line\033\[K\n"
}
# Blank out leftover lines from a previously longer render.
set extra [expr {$prevLineCount - [llength $lines]}]
for {set i 0} {$i < $extra} {incr i} {
$::realStdout puts -nonewline "\033\[K\n"
}
$::realStdout puts -nonewline "\033\[?7h"
if {[llength $lines] > $prevLineCount} {
set prevLineCount [llength $lines]
}
}
} {{this builtin-programs/terminal-ui.folk} {}}}} -errorcode NONE}
builtin-programs/shapes.folk claims builtin-programs/shapes.folk has demo {
# Center circle
Wish ()builtin-programs/shapes.folk claims builtin-programs/shapes.folk has demo {
# Center circle
Wish $this draws a circle
# Grid of shapes with varying thickness
set baseX -850
set baseY -200
set gridSpacing 130
# Row 0: Title
Wish $this draws text "triangle" with color skyblue offset [list $baseX [expr {$baseY - ($gridSpacing / 2.0)}]] scale 0.9
Wish $this draws text "square" with color green offset [list [expr {$baseX + $gridSpacing}] [expr {$baseY - ($gridSpacing / 2.0)}]] scale 0.9
Wish $this draws text "pentagon" with color gold offset [list [expr {$baseX + $gridSpacing*2}] [expr {$baseY - ($gridSpacing / 2.0)}]] scale 0.9
Wish $this draws text "hexagon" with color orange offset [list [expr {$baseX + $gridSpacing*3}] [expr {$baseY - ($gridSpacing / 2.0)}]] scale 0.9
# Row 1: Regular polygons with different colors and thickness
Wish $this draws a triangle with color skyblue thickness 2 offset [list $baseX [expr {$baseY}]]
Wish $this draws a square with color green thickness 4 offset [list [expr {$baseX + $gridSpacing}] [expr {$baseY}]]
Wish $this draws a pentagon with color gold thickness 6 offset [list [expr {$baseX + $gridSpacing*2}] [expr {$baseY}]]
Wish $this draws a hexagon with color orange thickness 8 offset [list [expr {$baseX + $gridSpacing*3}] [expr {$baseY}]]
# Row 2: Filled shapes
Wish $this draws a triangle with color skyblue filled true offset [list $baseX [expr {$baseY + $gridSpacing}]]
Wish $this draws a square with color green filled true offset [list [expr {$baseX + $gridSpacing}] [expr {$baseY + $gridSpacing}]]
Wish $this draws a pentagon with color gold filled true offset [list [expr {$baseX + $gridSpacing*2}] [expr {$baseY + $gridSpacing}]]
Wish $this draws a hexagon with color orange filled true offset [list [expr {$baseX + $gridSpacing*3}] [expr {$baseY + $gridSpacing}]]
# Row 3: Directional offset examples (replacing shift)
Wish $this draws a triangle with radius 40 offset "right 50%" color skyblue
Wish $this draws a square with radius 40 offset "left 50%" color green
Wish $this draws a pentagon with radius 40 offset "up 50%" color gold
Wish $this draws a hexagon with radius 40 offset "down 50%" color orange
# Row 4: Rectangles with different properties
Wish $this draws a rect with width 80 height 50 color cyan thickness 3 offset [list $baseX [expr {$baseY + $gridSpacing*3}]]
Wish $this draws a rect with width 80 height 50 color magenta filled true offset [list [expr {$baseX + $gridSpacing}] [expr {$baseY + $gridSpacing*3}]]
Wish $this draws a rect with width 80 height 50 offset "right 50%"
Wish $this draws a rect with width 80 height 50 offset "left 50%"
# Animated elements
When $this has region /r/ & the clock time is /t/ {
lassign [region angle $r] angle
for {set i 0} {$i < 8} {incr i} {
set offsetVector [list [sin [+ [- $i $t] $angle]] [* 2 [cos [+ [- $i $t] $angle]]]]
set vector [::vec2::scale $offsetVector [+ [* $i $i] 15]]
Wish $this draws a circle with radius $i color palegoldenrod offset $vector
}
}
When $this has region /r/ & the clock time is /t/ {
lassign [region centroid $r] x y
set fillVal [expr {round(sin($t) * 2)}]
set fill [expr {$fillVal % 2 == 0}]
set y [- $y 150]
Wish to draw a shape with sides 4 center [list [- $x 200] $y] radius 60 color white filled $fill
Wish to draw text with position [list [- $x 200] [+ $y 14]] scale 1.5 text "$fillVal" color red
}
When $this has region /r/ & the clock time is /t/ {
lassign [region centroid $r] x y
set fillVal [expr {round($t * 2)}]
set fill [expr {$fillVal % 2 == 0}]
set y [- $y 150]
Wish to draw a shape with sides 4 center [list [+ $x 200] $y] radius 60 color white filled $fill
Wish to draw text with position [list [+ $x 200] [+ $y 14]] scale 1.5 text "$fill" color red
}
Wish $this is outlined white
}
builtin-programs/editor-control.folk wishes the web server handles route /editor-control with hidden (
[ m518:0 () ]
)builtin-programs/editor-control.folk wishes the web server handles route /editor-control with hidden true handler {applyBlock {
html {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Editor copy/paste</title>
<script src="/lib/folk.js"></script>
</head>
<body>
<span id="status">Status</span>
<p>
Select a keyboard: <select id="keyboard-select"></select>
</p>
<textarea id="code" cols="120" rows="40"></textarea>
<script>
const ws = new FolkWS(document.getElementById('status'));
const keyboardSelect = document.querySelector("#keyboard-select");
const textarea = document.querySelector("#code");
var currentKeyboard = null;
var programCode = ""; // not the same as editor code
var cursorPosition = [0, 0];
// temporarily disable event processing after sending new code to prevent recursive event sends
var allowLocalEventsToProcess = true;
var allowRemoteEventsToProcess = true;
var _remoteTimoutHandle;
var _localTimeoutHandle;
function disableRemoteEventProcessing(durationMs) {
if (_remoteTimoutHandle) clearTimeout(_remoteTimoutHandle);
allowRemoteEventsToProcess = false;
_remoteTimoutHandle = setTimeout(() => {
allowRemoteEventsToProcess = true;
}, durationMs);
}
function disableLocalEventProcessing(durationMs) {
if (_localTimeoutHandle) clearTimeout(_localTimeoutHandle);
allowLocalEventsToProcess = false;
_localTimeoutHandle = setTimeout(() => {
allowLocalEventsToProcess = true;
}, durationMs);
}
function updateProgramCode() {
disableRemoteEventProcessing(500);
const { page, kbPath } = currentKeyboard;
const currentCode = textarea.value;
programCode = currentCode;
const id = page + kbPath;
ws.run(tcl`
Hold (non-capturing) (on builtin-programs/editor.folk) ${"cursor" + kbPath} {
Claim the ${kbPath} cursor is [list ${cursorPosition[0]} ${cursorPosition[1]}]
Hold (on builtin-programs/editor.folk) ${"code" + kbPath} {
Claim ${id} has program code [binary decode base64 ${btoa(currentCode)}]
Claim ${id} has editor code [binary decode base64 ${btoa(currentCode)}]
}
}
`);
}
function updateCursorAndCode(ev) {
if (!allowLocalEventsToProcess) return;
disableRemoteEventProcessing(500);
const { page, kbPath } = currentKeyboard;
const newCode = ev.target.value;
// figure out cursor position
const currentPosition = textarea.selectionStart;
const linesBefore = newCode.substring(0, currentPosition).split("\n");
const y = linesBefore.length - 1;
const x = linesBefore[linesBefore.length - 1].length;
cursorPosition = [x, y];
const id = page + kbPath;
ws.run(tcl`
Hold (non-capturing) (on builtin-programs/editor.folk) ${"cursor" + kbPath} {
Claim the ${kbPath} cursor is [list ${x} ${y}]
Hold (on builtin-programs/editor.folk) ${"code" + kbPath} {
Claim ${id} has program code [binary decode base64 ${btoa(programCode)}]
Claim ${id} has editor code [binary decode base64 ${btoa(newCode)}]
}
}
`);
}
textarea.addEventListener("input", updateCursorAndCode);
textarea.addEventListener("selectionchange", updateCursorAndCode);
textarea.addEventListener("keydown", ev => {
if(ev.keyCode === 83 /* s */ && (navigator.platform.match("Mac") ? ev.metaKey : ev.ctrlKey)) {
ev.preventDefault();
updateProgramCode();
}
});
var lastKeyboard; // to clean up the previous keyboard when another is picked
async function selectKeyboard({ page, kbPath }) {
if (lastKeyboard) lastKeyboard.stop();
currentKeyboard = { page, kbPath };
const id = page + kbPath;
lastKeyboard = await ws.watch(`${id} has base64 editor code /editorCode/ program code /programCode/ & the ${kbPath} cursor is /cursor/`, {
add: ({ editorCode, programCode: _programCode, cursor }) => {
if (!allowRemoteEventsToProcess) return;
disableLocalEventProcessing(500);
programCode = atob(_programCode);
editorCode = atob(editorCode);
textarea.value = editorCode;
// figure out where the cursor is
let [x, y] = loadList(cursor);
x = parseInt(x); y = parseInt(y);
cursorPosition = [x, y];
const lines = editorCode.split("\n");
let pos = 0;
for (let i = 0; i < y; i++) {
pos += lines[i].length + 1; // + 1 for newline
}
pos += x;
textarea.focus();
textarea.selectionStart = pos;
textarea.selectionEnd = pos;
}
});
}
// update keyboard list as it changes
ws.watchCollected("/page/ is an editor & /page/ is a keyboard with path /kbPath/", keyboards => {
keyboardSelect.innerHTML = "";
for (let keyboard of keyboards) {
let {page, kbPath} = keyboard;
keyboardSelect.innerHTML += `<option value="${JSON.stringify(keyboard)}">${page} (${kbPath})</option>`;
}
if (keyboards.length === 1) {
selectKeyboard(keyboards[0]);
}
});
// fired when selected keyboard changes
keyboardSelect.addEventListener("input", (ev) => {
selectKeyboard(JSON.parse(ev.target.value));
});
</script>
</body>
</html>
}
} {{this builtin-programs/editor-control.folk} {} {}}}
builtin-programs/draw/apriltags.folk wishes the GPU compiles pipeline apriltag {
{vec2 viewport m (
[ m23471:0 (s34181:0) ]
)builtin-programs/draw/apriltags.folk wishes the GPU compiles pipeline apriltag {
{vec2 viewport mat3 surfaceToClip vec4 background
uvec4 tagBitsVec vec2 a vec2 b vec2 c vec2 d} {
vec2 vertices[6] = vec2[6](a, b, c, a, c, d);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {fn invBilinear} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
vec2 uv = invBilinear(surfaceXy.xy, a, b, c, d);
int x = int(uv.x * 10); int y = int(uv.y * 10);
int bitIdx = y * 10 + x;
uint bit = (tagBitsVec[bitIdx / 32] >> (bitIdx % 32)) & 0x1;
return bit == 1 ? background : vec4(0, 0, 0, 1);
}
}
builtin-programs/draw/image.folk wishes the GPU compiles pipeline image {
{vec2 viewport mat3 sur (
[ m23484:0 (s33276:0) ]
)builtin-programs/draw/image.folk wishes the GPU compiles pipeline image {
{vec2 viewport mat3 surfaceToClip
sampler2D image vec2 a vec2 b vec2 c vec2 d} {
vec2 vertices[6] = vec2[6](a, b, c, a, c, d);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {fn invBilinear} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
vec2 uv = invBilinear(surfaceXy.xy, a, b, c, d);
if( max( abs(uv.x-0.5), abs(uv.y-0.5))<0.5 ) {
vec4 texColor = texture(image, uv);
if (texColor.a < 0.01) {
return vec4(0.0);
}
return texColor;
}
return vec4(0.0);
}}
builtin-programs/draw/image.folk wishes the GPU loads image {width {100} height {100} components {3} ()builtin-programs/draw/image.folk wishes the GPU loads image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} as texture
builtin-programs/draw/image.folk wishes the GPU draws pipeline image onto canvas {11 canvas} with arg ()builtin-programs/draw/image.folk wishes the GPU draws pipeline image onto canvas {11 canvas} with arguments {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} 18 {0 0} {0.100666666667 0} {0.100666666667 0.100666666667} {0 0.100666666667}}
builtin-programs/draw/image.folk wishes to draw an image onto 11 with image {width {100} height {100} ()builtin-programs/draw/image.folk wishes to draw an image onto 11 with image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} position {0 0} anchor topleft width 0.100666666667
builtin-programs/draw/image.folk wishes 11 displays image https://blob.gifcities.org/gifcities/IC6U7E (
[ m33952:727 (s14361:865) ]
)builtin-programs/draw/image.folk wishes 11 displays image https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif with scale 1.0
builtin-programs/draw/image.folk wishes 11 displays gif {frames {{width {100} height {100} components (
[ m25741:915 (s2883:1084) ]
)builtin-programs/draw/image.folk wishes 11 displays gif {frames {{width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0346e20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03558a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b035cde0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0364320}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b036b860}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0372da0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b037a2e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0381820}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0388d60}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03902a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03977e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b039ed20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03a6260}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03ad7a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03b4ce0}}} delays {250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250} width 100 height 100} with scale 1.0
builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ la (
[ m947:0 () ]
)builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}} is an image loader
builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ la (
[ m967:0 () ]
)builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}} is an image loader
builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ la (
[ m1001:0 () ]
)builtin-programs/draw/image.folk claims {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}} is an image loader
builtin-programs/draw/image.folk claims the image loader is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ (
[ m1004:0 (s1775:0) ]
[ m1005:0 (s1776:0) ]
[ m1455:0 (s2338:0 s2339:0 s2342:0 s2343:0 s2349:0 s2350:0 s2353:0 s2354:0) ]
)builtin-programs/draw/image.folk claims the image loader is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}} {{this builtin-programs/draw/image.folk} {} {} {loaders {{loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}} {{this builtin-programs/draw/image.folk} {} {} {gifLib <C:cfiled3kiwc>} {^gifLoader {im {
upvar coerceToImage coerceToImage
if {[string match "*gif" $im]} {
set gif [$gifLib loadGif $im]
if {$coerceToImage} {
return [lindex [dict get $gif frames] 0]
}
# WARNING: This is not an Image object -- it's a Gif
# object and requires special handling by the caller.
return $gif
}
} {builtin-programs/draw/image.folk 20}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}} {{this builtin-programs/draw/image.folk} {} {} {pngLib <C:cfileimXyHY>} {^pngLoader {im {
if {[string match "*png" $im]} {
return [$pngLib loadPng $im]
}
} {builtin-programs/draw/image.folk 11}}}}}} {loader {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}} {{this builtin-programs/draw/image.folk} {} {} {jpegLib <C:cfileZXB3iE>} {^jpegLoader {im {
if {[string match "*jpg" $im] || [string match "*jpeg" $im]} {
return [$jpegLib loadJpeg $im]
}
} {builtin-programs/draw/image.folk 2}}}}}}}} {^loadImage {{im {coerceToImage 1}} \n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ image\ path\ \$im\ maps\ to\ cached\ image\ /cachedIm/\]\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$results\]\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[dict\ get\ \[lindex\ \$results\ 0\]\ cachedIm\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ impath\ \$im\n\ \ \ \ \ \ \ \ if\ \{\[string\ match\ \"http*://*\"\ \$impath\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ im\ /tmp/\[regsub\ -all\ \{\\W+\}\ \$impath\ \"_\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$im\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ exec\ curl\ -s\ -L\ -o\$im\ \$impath\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ path\ \[expr\ \{\[string\ index\ \$im\ 0\]\ eq\ \"/\"\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$im\ :\ \"\$::env(HOME)/folk-images/\$im\"\}\]\n\ \ \ \ \ \ \ \ if\ \{!\[file\ exists\ \$path\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ path\ \[file\ join\ \[pwd\]\ \$im\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ loaderResult\ \$loaders\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ loader\ \[dict\ get\ \$loaderResult\ loader\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ result\ \[\{*\}\$loader\ \$path\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$result\ ne\ \{\}\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ \[list\ cache\ \$impath\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Claim\ the\ image\ path\ \$impath\ maps\ to\ cached\ image\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\ \$result\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$im\n\ \ \ \ {builtin-programs/draw/image.folk 40}}}}}
builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/VictorMonoRegular ()builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/VictorMonoRegular.png maps to cached image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c298ac0}}
builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/PTSans-Regular.pn ()builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/PTSans-Regular.png maps to cached image {width {200} height {200} components {3} bytesPerRow {600} uniq {0} data {(uint8_t*) 0x79d17c2f4430}}
builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/CourierPrimeCode. ()builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/CourierPrimeCode.png maps to cached image {width {192} height {192} components {3} bytesPerRow {576} uniq {0} data {(uint8_t*) 0x79d17c42a090}}
builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/NeomatrixCode.png ()builtin-programs/draw/image.folk claims the image path /home/folk/folk/vendor/fonts/NeomatrixCode.png maps to cached image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c466c40}}
builtin-programs/draw/image.folk claims the image path https://blob.gifcities.org/gifcities/IC6U7E6P2 ()builtin-programs/draw/image.folk claims the image path https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif maps to cached image {frames {{width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0346e20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03558a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b035cde0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0364320}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b036b860}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0372da0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b037a2e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0381820}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b0388d60}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03902a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03977e0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b039ed20}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03a6260}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03ad7a0}} {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b03b4ce0}}} delays {250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250} width 100 height 100}
builtin-programs/draw/fill.folk wishes the GPU compiles pipeline fillTriangle {
{mat3 surfaceToCl (
[ m23507:0 (s34116:0) ]
)builtin-programs/draw/fill.folk wishes the GPU compiles pipeline fillTriangle {
{mat3 surfaceToClip vec2 p0 vec2 p1 vec2 p2 vec4 color} {
vec2 vertices[6] = vec2[6](p0, p1, p2, p0, p0, p0);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {
return color;
}
}
builtin-programs/draw/fill.folk wishes the GPU draws pipeline fillTriangle onto canvas {monitor canva (
[ m6792:1066 () ]
)builtin-programs/draw/fill.folk wishes the GPU draws pipeline fillTriangle onto canvas {monitor canvas} with arguments {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2769.84476267 1367.39171626} {2530.60087726 1399.3331699} {2539.32201432 1175.33046251} {0.0 0.0 0.0 1.0}} layer 100
builtin-programs/draw/fill.folk wishes the GPU draws pipeline fillTriangle onto canvas {monitor canva (
[ m6790:1066 () ]
)builtin-programs/draw/fill.folk wishes the GPU draws pipeline fillTriangle onto canvas {monitor canvas} with arguments {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2770.94576434 1140.12894428} {2769.84476267 1367.39171626} {2539.32201432 1175.33046251} {0.0 0.0 0.0 1.0}} layer 100
builtin-programs/draw/dashed-line.folk wishes the GPU compiles pipeline dashed-line {
{vec2 viewp (
[ m23525:0 (s34648:0) ]
)builtin-programs/draw/dashed-line.folk wishes the GPU compiles pipeline dashed-line {
{vec2 viewport mat3 surfaceToClip
vec2 from vec2 to float thickness vec4 color
float dashlength float dashoffset} {
vec2 dir = normalize(to - from);
vec2 perp = vec2(-dir.y, dir.x) * thickness/2.0;
vec2 vertices[6] = vec2[6](
from + perp,
from - perp,
to - perp,
from + perp,
to - perp,
to + perp
);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
float l = length(to - from);
// How far are we along the line? (in pixels)
float t = dot(surfaceXy.xy - from, to - from) / l + dashoffset;
vec2 d = (to - from) / l;
vec2 q = (surfaceXy.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 && floor(mod(t / dashlength, 2.0)) == 0.0) ? color : vec4(0.0);
}
}
builtin-programs/draw/line.folk wishes the GPU compiles pipeline line {
{vec2 viewport mat3 surfa (
[ m23544:0 (s34568:0) ]
)builtin-programs/draw/line.folk wishes the GPU compiles pipeline line {
{vec2 viewport mat3 surfaceToClip
vec2 from vec2 to float thickness vec4 color} {
vec2 dir = normalize(to - from);
vec2 perp = vec2(-dir.y, dir.x) * thickness/2.0;
vec2 vertices[6] = vec2[6](
from + perp,
from - perp,
to - perp,
from + perp,
to - perp,
to + perp
);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
float l = length(to - from);
vec2 d = (to - from) / l;
vec2 q = (surfaceXy.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) ? color : vec4(0.0);
}
}
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {54 canvas} with insta (
[ m23374:1062 () ]
)builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {54 canvas} with instances {{{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0 0} {0.211 0} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.211 0} {0.211 0.139} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.211 0.139} {0 0.139} 0.01 {0.0 0.501960784314 0.0 1.0}} {{1024 1024} {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0 0.139} {0 0} 0.01 {0.0 0.501960784314 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {82 canvas} with insta (
[ m47743:1061 () ]
)builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {82 canvas} with instances {{{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0} {0.2159 0} 0.01 {1.0 0.0 0.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0} {0.2159 0.1397} 0.01 {1.0 0.0 0.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0.1397} {0 0.1397} 0.01 {1.0 0.0 0.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0.1397} {0 0} 0.01 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {83 canvas} with insta (
[ m47762:1064 () ]
)builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {83 canvas} with instances {{{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0} {0.2159 0} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0} {0.2159 0.1397} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0.2159 0.1397} {0 0.1397} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}} {0 0.1397} {0 0} 0.01 {1.0 1.0 1.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {54-display canvas} wi ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {54-display canvas} with instances {{{1024 1024} {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}} {0 0} {0.1055 0} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}} {0.1055 0} {0.1055 0.0695} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}} {0.1055 0.0695} {0 0.0695} 0.01 {1.0 1.0 1.0 1.0}} {{1024 1024} {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}} {0 0.0695} {0 0} 0.01 {1.0 1.0 1.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1967.81565509 2061.83554238} {1937.05760988 2335.00071436} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1937.05760988 2335.00071436} {1779.91543024 2344.09812945} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1779.91543024 2344.09812945} {1815.57230363 2074.26808682} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1815.57230363 2074.26808682} {1967.81565509 2061.83554238} 4 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2169.43695595 1549.1745993} {2147.67411821 1790.78402596} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2147.67411821 1790.78402596} {1996.25681495 1806.51253651} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1996.25681495 1806.51253651} {2022.6268608 1567.44068475} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2022.6268608 1567.44068475} {2169.43695595 1549.1745993} 4 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1996.25681495 1806.51253652} {1967.81565511 2061.83554238} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1967.81565511 2061.83554238} {1815.57230361 2074.26808682} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1815.57230361 2074.26808682} {1848.64128318 1821.82810017} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1848.64128318 1821.82810017} {1996.25681495 1806.51253652} 4 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2022.62686079 1567.44068474} {1996.25681496 1806.51253652} 4 {0.0 0.501960784314 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1996.25681496 1806.51253652} {1848.64128317 1821.82810017} 4 {0.0 0.501960784314 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1848.64128317 1821.82810017} {1879.38473133 1585.24979987} 4 {0.0 0.501960784314 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1879.38473133 1585.24979987} {2022.62686079 1567.44068474} 4 {0.0 0.501960784314 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2124.11746003 2049.04528994} {2098.54045538 2325.6140552} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2098.54045538 2325.6140552} {1937.05760987 2335.00071436} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1937.05760987 2335.00071436} {1967.81565511 2061.83554238} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1967.81565511 2061.83554238} {2124.11746003 2049.04528994} 4 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with ()builtin-programs/draw/line.folk wishes the GPU draws pipeline line onto canvas {monitor canvas} with instances {{{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2147.6741182 1790.78402597} {2124.11746004 2049.04528994} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {2124.11746004 2049.04528994} {1967.81565509 2061.83554238} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1967.81565509 2061.83554238} {1996.25681496 1806.51253652} 4 {1.0 0.0 0.0 1.0}} {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {1996.25681496 1806.51253652} {2147.6741182 1790.78402597} 4 {1.0 0.0 0.0 1.0}}} layer 0
builtin-programs/draw/circle.folk wishes the GPU compiles pipeline circle {
{vec2 viewport mat3 s (
[ m23545:0 (s33464:0) ]
)builtin-programs/draw/circle.folk wishes the GPU compiles pipeline circle {
{vec2 viewport mat3 surfaceToClip
vec2 center float radius float thickness vec4 color int filled} {
float r = radius + thickness;
vec2 vertices[6] = vec2[6](
center - r,
vec2(center.x + r, center.y - r),
vec2(center.x - r, center.y + r),
vec2(center.x + r, center.y - r),
center + r,
vec2(center.x - r, center.y + r)
);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
float dist = length(surfaceXy.xy - center) - radius;
if (filled == 1) {
return (dist < thickness) ? color : vec4(0.0);
} else {
return (dist < thickness && dist > 0.0) ? color : vec4(0.0);
}
}
}
builtin-programs/draw/color-map.folk claims the color map is {aliceblue {0.941176470588 0.97254901960 (
[ m488:0 (s779:0) ]
[ m492:0 (s783:0 s792:0 s796:0) ]
[ m493:0 (s786:0) ]
[ m496:0 (s795:0) ]
[ m1456:0 (s2331:0) ]
)builtin-programs/draw/color-map.folk claims the color map is {aliceblue {0.941176470588 0.972549019608 1.0 1.0} antiquewhite {0.980392156863 0.921568627451 0.843137254902 1.0} aqua {0.0 1.0 1.0 1.0} aquamarine {0.498039215686 1.0 0.83137254902 1.0} azure {0.941176470588 1.0 1.0 1.0} beige {0.960784313725 0.960784313725 0.862745098039 1.0} bisque {1.0 0.894117647059 0.76862745098 1.0} black {0.0 0.0 0.0 1.0} blanchedalmond {1.0 0.921568627451 0.803921568627 1.0} blue {0.0 0.0 1.0 1.0} blueviolet {0.541176470588 0.16862745098 0.886274509804 1.0} brown {0.647058823529 0.164705882353 0.164705882353 1.0} burlywood {0.870588235294 0.721568627451 0.529411764706 1.0} cadetblue {0.372549019608 0.619607843137 0.627450980392 1.0} chartreuse {0.498039215686 1.0 0.0 1.0} chocolate {0.823529411765 0.411764705882 0.117647058824 1.0} coral {1.0 0.498039215686 0.313725490196 1.0} cornflowerblue {0.392156862745 0.58431372549 0.929411764706 1.0} cornsilk {1.0 0.972549019608 0.862745098039 1.0} crimson {0.862745098039 0.078431372549 0.235294117647 1.0} cyan {0.0 1.0 1.0 1.0} darkblue {0.0 0.0 0.545098039216 1.0} darkcyan {0.0 0.545098039216 0.545098039216 1.0} darkgoldenrod {0.721568627451 0.525490196078 0.043137254902 1.0} darkgray {0.662745098039 0.662745098039 0.662745098039 1.0} darkgreen {0.0 0.392156862745 0.0 1.0} darkgrey {0.662745098039 0.662745098039 0.662745098039 1.0} darkkhaki {0.741176470588 0.717647058824 0.419607843137 1.0} darkmagenta {0.545098039216 0.0 0.545098039216 1.0} darkolivegreen {0.333333333333 0.419607843137 0.18431372549 1.0} darkorange {1.0 0.549019607843 0.0 1.0} darkorchid {0.6 0.196078431373 0.8 1.0} darkred {0.545098039216 0.0 0.0 1.0} darksalmon {0.913725490196 0.588235294118 0.478431372549 1.0} darkseagreen {0.560784313725 0.737254901961 0.560784313725 1.0} darkslateblue {0.282352941176 0.239215686275 0.545098039216 1.0} darkslategray {0.18431372549 0.309803921569 0.309803921569 1.0} darkslategrey {0.18431372549 0.309803921569 0.309803921569 1.0} darkturquoise {0.0 0.807843137255 0.819607843137 1.0} darkviolet {0.580392156863 0.0 0.827450980392 1.0} deeppink {1.0 0.078431372549 0.576470588235 1.0} deepskyblue {0.0 0.749019607843 1.0 1.0} dimgray {0.411764705882 0.411764705882 0.411764705882 1.0} dimgrey {0.411764705882 0.411764705882 0.411764705882 1.0} dodgerblue {0.117647058824 0.564705882353 1.0 1.0} firebrick {0.698039215686 0.133333333333 0.133333333333 1.0} floralwhite {1.0 0.980392156863 0.941176470588 1.0} forestgreen {0.133333333333 0.545098039216 0.133333333333 1.0} fuchsia {1.0 0.0 1.0 1.0} gainsboro {0.862745098039 0.862745098039 0.862745098039 1.0} ghostwhite {0.972549019608 0.972549019608 1.0 1.0} gold {1.0 0.843137254902 0.0 1.0} goldenrod {0.854901960784 0.647058823529 0.125490196078 1.0} gray {0.501960784314 0.501960784314 0.501960784314 1.0} green {0.0 0.501960784314 0.0 1.0} greenyellow {0.678431372549 1.0 0.18431372549 1.0} grey {0.501960784314 0.501960784314 0.501960784314 1.0} honeydew {0.941176470588 1.0 0.941176470588 1.0} hotpink {1.0 0.411764705882 0.705882352941 1.0} indianred {0.803921568627 0.360784313725 0.360784313725 1.0} indigo {0.294117647059 0.0 0.509803921569 1.0} ivory {1.0 1.0 0.941176470588 1.0} khaki {0.941176470588 0.901960784314 0.549019607843 1.0} lavender {0.901960784314 0.901960784314 0.980392156863 1.0} lavenderblush {1.0 0.941176470588 0.960784313725 1.0} lawngreen {0.486274509804 0.988235294118 0.0 1.0} lemonchiffon {1.0 0.980392156863 0.803921568627 1.0} lightblue {0.678431372549 0.847058823529 0.901960784314 1.0} lightcoral {0.941176470588 0.501960784314 0.501960784314 1.0} lightcyan {0.878431372549 1.0 1.0 1.0} lightgoldenrodyellow {0.980392156863 0.980392156863 0.823529411765 1.0} lightgray {0.827450980392 0.827450980392 0.827450980392 1.0} lightgreen {0.564705882353 0.933333333333 0.564705882353 1.0} lightgrey {0.827450980392 0.827450980392 0.827450980392 1.0} lightpink {1.0 0.713725490196 0.756862745098 1.0} lightsalmon {1.0 0.627450980392 0.478431372549 1.0} lightseagreen {0.125490196078 0.698039215686 0.666666666667 1.0} lightskyblue {0.529411764706 0.807843137255 0.980392156863 1.0} lightslategray {0.466666666667 0.533333333333 0.6 1.0} lightslategrey {0.466666666667 0.533333333333 0.6 1.0} lightsteelblue {0.690196078431 0.76862745098 0.870588235294 1.0} lightyellow {1.0 1.0 0.878431372549 1.0} lime {0.0 1.0 0.0 1.0} limegreen {0.196078431373 0.803921568627 0.196078431373 1.0} linen {0.980392156863 0.941176470588 0.901960784314 1.0} magenta {1.0 0.0 1.0 1.0} maroon {0.501960784314 0.0 0.0 1.0} mediumaquamarine {0.4 0.803921568627 0.666666666667 1.0} mediumblue {0.0 0.0 0.803921568627 1.0} mediumorchid {0.729411764706 0.333333333333 0.827450980392 1.0} mediumpurple {0.576470588235 0.439215686275 0.858823529412 1.0} mediumseagreen {0.235294117647 0.701960784314 0.443137254902 1.0} mediumslateblue {0.482352941176 0.407843137255 0.933333333333 1.0} mediumspringgreen {0.0 0.980392156863 0.603921568627 1.0} mediumturquoise {0.282352941176 0.819607843137 0.8 1.0} mediumvioletred {0.780392156863 0.0823529411765 0.521568627451 1.0} midnightblue {0.0980392156863 0.0980392156863 0.439215686275 1.0} mintcream {0.960784313725 1.0 0.980392156863 1.0} mistyrose {1.0 0.894117647059 0.882352941176 1.0} moccasin {1.0 0.894117647059 0.709803921569 1.0} navajowhite {1.0 0.870588235294 0.678431372549 1.0} navy {0.0 0.0 0.501960784314 1.0} oldlace {0.992156862745 0.960784313725 0.901960784314 1.0} olive {0.501960784314 0.501960784314 0.0 1.0} olivedrab {0.419607843137 0.556862745098 0.137254901961 1.0} orange {1.0 0.647058823529 0.0 1.0} orangered {1.0 0.270588235294 0.0 1.0} orchid {0.854901960784 0.439215686275 0.839215686275 1.0} palegoldenrod {0.933333333333 0.909803921569 0.666666666667 1.0} palegreen {0.596078431373 0.98431372549 0.596078431373 1.0} paleturquoise {0.686274509804 0.933333333333 0.933333333333 1.0} palevioletred {0.858823529412 0.439215686275 0.576470588235 1.0} papayawhip {1.0 0.937254901961 0.835294117647 1.0} peachpuff {1.0 0.854901960784 0.725490196078 1.0} peru {0.803921568627 0.521568627451 0.247058823529 1.0} pink {1.0 0.752941176471 0.796078431373 1.0} plum {0.866666666667 0.627450980392 0.866666666667 1.0} powderblue {0.690196078431 0.878431372549 0.901960784314 1.0} purple {0.501960784314 0.0 0.501960784314 1.0} rebeccapurple {0.4 0.2 0.6 1.0} red {1.0 0.0 0.0 1.0} rosybrown {0.737254901961 0.560784313725 0.560784313725 1.0} royalblue {0.254901960784 0.411764705882 0.882352941176 1.0} saddlebrown {0.545098039216 0.270588235294 0.0745098039216 1.0} salmon {0.980392156863 0.501960784314 0.447058823529 1.0} sandybrown {0.956862745098 0.643137254902 0.376470588235 1.0} seagreen {0.180392156863 0.545098039216 0.341176470588 1.0} seashell {1.0 0.960784313725 0.933333333333 1.0} sienna {0.627450980392 0.321568627451 0.176470588235 1.0} silver {0.752941176471 0.752941176471 0.752941176471 1.0} skyblue {0.529411764706 0.807843137255 0.921568627451 1.0} slateblue {0.41568627451 0.352941176471 0.803921568627 1.0} slategray {0.439215686275 0.501960784314 0.564705882353 1.0} slategrey {0.439215686275 0.501960784314 0.564705882353 1.0} snow {1.0 0.980392156863 0.980392156863 1.0} springgreen {0.0 1.0 0.498039215686 1.0} steelblue {0.274509803922 0.509803921569 0.705882352941 1.0} tan {0.823529411765 0.705882352941 0.549019607843 1.0} teal {0.0 0.501960784314 0.501960784314 1.0} thistle {0.847058823529 0.749019607843 0.847058823529 1.0} tomato {1.0 0.388235294118 0.278431372549 1.0} turquoise {0.250980392157 0.878431372549 0.81568627451 1.0} violet {0.933333333333 0.509803921569 0.933333333333 1.0} wheat {0.960784313725 0.870588235294 0.701960784314 1.0} white {1.0 1.0 1.0 1.0} whitesmoke {0.960784313725 0.960784313725 0.960784313725 1.0} yellow {1.0 1.0 0.0 1.0} yellowgreen {0.603921568627 0.803921568627 0.196078431373 1.0}}
builtin-programs/print/print.folk claims the paper formats are {
letter {tagInnerSideLength 70 ()builtin-programs/print/print.folk claims the paper formats are {
letter {tagInnerSideLength 70 pageSize {612 792}}
a4 {tagInnerSideLength 70 pageSize {595 842}}
indexcard {tagInnerSideLength 70 pageSize {612 792}}
}
builtin-programs/print/print.folk claims the print library is <C:cfileDzXJHE> (
[ m1041:0 (s1821:0) ]
[ m1045:0 (s1830:0) ]
[ m1049:0 (s1833:0) ]
)builtin-programs/print/print.folk claims the print library is <C:cfileDzXJHE>
builtin-programs/print/print.folk claims the codeToPostScript is {apply \{fn\ envStack\ args\}\ \{\n\ (
[ m1046:0 (s1831:0) ]
[ m1048:0 (s1835:0 s1836:0 s1837:0) ]
)builtin-programs/print/print.folk claims the codeToPostScript is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}
builtin-programs/web/block-stats.folk wishes the web server handles route /block-stats with handler { (
[ m522:0 () ]
)builtin-programs/web/block-stats.folk wishes the web server handles route /block-stats with handler {applyBlock {
set stats [lsort -command {apply {{a b} {
lassign $a _ ewma_a count_a
lassign $b _ ewma_b count_b
expr {$ewma_b * $count_b - $ewma_a * $count_a < 0 ? -1 :
$ewma_b * $count_b - $ewma_a * $count_a > 0 ? 1 : 0}
}}} [__blockRuntimeStats]]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Block runtime stats</title>
</head>
<body>
<h2>Block runtime stats (EWMA)</h2>
<table>
<tr><th>Location</th><th>EWMA (µs)</th><th>Count</th></tr>
[join [lmap entry $stats {
lassign $entry key ewma_ns count
subst {<tr>
<td>[htmlEscape $key]</td>
<td>[format "%.1f" [expr {$ewma_ns / 1000.0}]]</td>
<td>$count</td>
</tr>}
}] "\n"]
</table>
</body>
</html>
}]
} {{this builtin-programs/web/block-stats.folk} {} {}}}
builtin-programs/web/setup.folk wishes the web server handles route /setup with nav <button>Setup</bu (
[ m537:0 () ]
)builtin-programs/web/setup.folk wishes the web server handles route /setup with nav <button>Setup</button> handler {applyBlock \n\ \ \ \ html\ \[subst\ \{\n<!DOCTYPE\ html>\n<html>\n<head>\n<title>Folk\ setup</title>\n<script\ src=\"/lib/folk.js\"></script>\n</head>\n\n<body>\n<script>\nconst\ folk\ =\ new\ FolkWS()\;\n\nlet\ hasSeenHandlers\ =\ false\;\nfolk.watchCollected(`/someone/\ wishes\ the\ web\ server\ handles\ route\ \"/setup\"\ with\ handler\ /handler/`,\ handlers\ =>\ \{\n\ \ \ \ if\ (hasSeenHandlers)\ \{\n\ \ \ \ \ \ \ \ window.location.reload()\;\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ hasSeenHandlers\ =\ true\;\n\ \ \ \ \}\n\})\;\n</script>\n\n<h1>Folk\ setup</h1>\n<!--\ \n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Start\ service\ on\ boot</h2>\n\ \ \ \ \ LIST\ IF\ SYSTEMD\ SERVICE\ EXISTS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Configure\ user\ permissions</h2>\n\ \ \ \ \ LIST\ IF\ PART\ OF\ ALL\ GROUPS\n\ \ \ \ \ </div>\n\n\ \ \ \ \ <div>\n\ \ \ \ \ <h2>Errors</h2>\n\ \ \ \ \ LIST\ ALL\ ERRORS\n\ \ \ \ \ </div>\n-->\n<style>\n\ \ .mode-select\ .mode\ input\\\[type=radio\]\ \{\n\ \ \ \ \ \ display:\ none\;\n\ \ \}\n\ \ .mode-select\ .resolution:hover,\ \n\ \ .mode-select\ label:has(input\\\[type=radio\]):hover,\n\ \ .mode-select\ .resolution:hover\ +\ label,\n\ \ .mode-select\ .resolution:has(~\ label\ input\\\[type=radio\]:hover)\ \{\n\ \ \ \ \ \ background-color:\ #a8e6a3\;\n\ \ \ \ \ \ cursor:\ pointer\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #ccc\;\n\ \ \}\n\ \ .mode-select\ .mode:has(input:checked)\ .resolution,\n\ \ .mode-select\ label:has(input:checked)\ \{\n\ \ \ \ \ \ background-color:\ #27ae60\;\n\ \ \}\n\ \ .mode-select\ .resolution\ \{\n\ \ \ \ \ \ width:\ 100px\;\n\ \ \}\n\ \ .mode\ \{\n\ \ \ \ \ \ display:\ flex\;\n\ \ \ \ \ \ gap:\ 8px\;\n\ \ \ \ \ \ flex-wrap:\ wrap\;\n\ \ \}\n</style>\n\n<div\ class=\"mode-select\">\n\ \ <h2>Displays</h2>\n\ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <button\ onclick=\"dontUseDisplay()\"><strong>Don't\ use\ a\ display</strong></button>\n\ \ </div>\n\n\ \ \[HtmlWhen\ \$::thisNode\ has\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ display\ \$display\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingDisplay\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingDisplay\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ info\ \[dict\ get\ \$opts\ info\]\n\ \ \ \ set\ displayName\ \[dict\ get\ \$info\ name\]\n\n\ \ \ \ set\ modesByRegion\ \[dict\ create\]\n\ \ \ \ foreach\ mode\ \[dict\ getdef\ \$info\ modes\ \[list\]\]\ \{\n\ \ \ \ \ \ dict\ lappend\ modesByRegion\ \$mode(visibleRegion)\ \$mode\n\ \ \ \ \}\n\ \ \ \ set\ regions\ \[lsort\ -decreasing\ -integer\ -index\ 0\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ keys\ \$modesByRegion\]\]\n\n\ \ \ \ set\ displayId\ \[string\ map\ \{/\ _\}\ \$display\]\n\ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"display-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingDisplay\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$displayName</strong><br>\n\ \ \ \ \ \ \ \ \ \ \[if\ \{\[dict\ exists\ \$info\ physicalResolution\]\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Physical\ resolution:\ \[join\ \$info(physicalResolution)\ x\])\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ \[if\ \{\[llength\ \$regions\]\ >\ 0\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ mode:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ region\ \$regions\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$region\ width\ height\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lmap\ mode\ \[dict\ get\ \$modesByRegion\ \$region\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{dict\ get\ \$mode\ refreshRate\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ refreshRates\ \[lsort\ -decreasing\ -integer\ \$refreshRates\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$width\ height\ \$height\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"displayResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{width\}x\$\{height\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ refreshRate\ \$refreshRates\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"display-refreshRate-\$displayId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$width\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$height\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$refreshRate\ ==\ \$usingOpts(refreshRate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-display=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$width\ height\ \$height\ refreshRate\ \$refreshRate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"displayModeChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \[/\ \$refreshRate\ 1000\]\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ function\ dontUseDisplay()\ \{\n\ \ \ \ \ document.querySelectorAll('input\\\[type=\"checkbox\"\\\]\\\[name=\"display-enabled\"\]:checked').forEach(cb\ =>\ \{\n\ \ \ \ \ \ \ cb.checked\ =\ false\;\n\n\ \ \ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{cb.value\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \})\;\n\ \ \ \}\n\ \ \ function\ displayEnabledChange(event)\ \{\n\ \ \ \ \ //\ HACK:\ remove\ older-form\ display\ setup.\n\ \ \ \ \ folk.hold(`display`,\ '',\ 'builtin-programs/web/setup.folk',\ true)\;\n\n\ \ \ \ \ const\ display\ =\ this.value\;\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ if\ (display\ ===\ \"glfw\")\ \{\n\ \ \ \ \ \ \ \ \ //\ glfw\ doesn't\ have\ any\ mode\ settings\ (for\ now).\n\ \ \ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ width\ 640\ height\ 480\ refreshRate\ -1`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\n\ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \}\n\ \ \ function\ displayResolutionClicked(event)\ \{\n\ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ const\ firstRefreshRateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"display-refreshRate-\"\\\]\\\[data-display=\"\\\$\{display\}\"\]`\ +\n\ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ )\;\n\ \ \ \ \ firstRefreshRateRadio.checked\ =\ true\;\n\ \ \ \ \ firstRefreshRateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ \ function\ displayModeChange(event)\ \{\n\ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ const\ display\ =\ this.dataset.display\;\n\ \ \ \ \ \ \ const\ mode\ =\ this.value\;\n\ \ \ \ \ \ \ folk.hold(`display\ \\\$\{display\}`,\ `Wish\ \\\$::thisNode\ uses\ display\ \"\\\$\{display\}\"\ with\ \\\$\{mode\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \}\n\ \ \ \ \ event.preventDefault()\;\n\ \ \ \}\n\ \ </script>\n</div>\n\n<style>\n\ \ .crop-box\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ background:\ rgba(39,174,96,0.15)\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \ \ \ \ cursor:\ move\;\n\ \ \}\n\ \ .crop-handle\ \{\n\ \ \ \ \ \ position:\ absolute\;\n\ \ \ \ \ \ width:\ 12px\;\ height:\ 12px\;\n\ \ \ \ \ \ background:\ white\;\n\ \ \ \ \ \ border:\ 2px\ solid\ #27ae60\;\n\ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ pointer-events:\ auto\;\n\ \ \}\n\ \ .crop-handle\\\[data-corner=\"nw\"\]\ \{\ top:\ -7px\;\ left:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"ne\"\]\ \{\ top:\ -7px\;\ right:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"sw\"\]\ \{\ bottom:\ -7px\;\ left:\ -7px\;\ cursor:\ nesw-resize\;\ \}\n\ \ .crop-handle\\\[data-corner=\"se\"\]\ \{\ bottom:\ -7px\;\ right:\ -7px\;\ cursor:\ nwse-resize\;\ \}\n</style>\n<div\ class=\"mode-select\">\n\ \ <h2>Cameras</h2>\n\ \ \[HtmlWhen\ \$::thisNode\ has\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ HtmlWhen\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[list\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ \$camera\ with\ /...usingOpts/\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ are\ /results/\ \{\n\ \ \ \ set\ isUsingCamera\ \$(\[llength\ \$results\]\ >=\ 1)\n\ \ \ \ if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ set\ usingOpts\ \[dict\ get\ \[lindex\ \$results\ 0\]\ usingOpts\]\n\ \ \ \ \}\n\n\ \ \ \ set\ resolutions\ \[list\]\n\ \ \ \ foreach\ format\ \[dict\ get\ \$opts\ formats\]\ \{\n\ \ \ \ \ \ \ \ #\ For\ now,\ we\ only\ support\ MJPG.\ The\ more\ raw\ formats\ are\n\ \ \ \ \ \ \ \ #\ rarely\ used\ by\ cameras\ at\ even\ medium\ resolutions\ and\n\ \ \ \ \ \ \ \ #\ framerates,\ anyway,\ so\ it's\ only\ worth\ supporting\ MJPG.\n\ \ \ \ \ \ \ \ if\ \{\$format(fourcc)\ eq\ \"MJPG\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ resolutions\ \{*\}\$format(resolutions)\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ resolutions\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{\n\ \ \ \ \ \ \ \ expr\ \{\[dict\ get\ \$b\ width\]\ -\ \[dict\ get\ \$a\ width\]\}\n\ \ \ \ \}\}\}\ \$resolutions\]\n\n\ \ \ \ if\ \{\[llength\ \$resolutions\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ #\ Cameras\ often\ have\ extra\ camera\ devices\ with\ no\ formats\ (or\ no\n\ \ \ \ \ \ #\ MJPG,\ at\ least)\ for\ some\ reason.\ Not\ very\ useful\ for\ us.\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)<br>\n\ \ \ \ \ \ \ \ (no\ supported\ formats)\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ set\ cameraId\ \[string\ map\ \{/\ _\}\ \$camera\]\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ <div\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"camera-enabled\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\$isUsingCamera\ ?\ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraEnabledChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ <strong>\$camera</strong>\ (<code>\[dict\ getdef\ \$opts\ card\ \"\"\]</code>)\n\ \ \ \ \ \ \ \ </label>\n\n\ \ \ \ \ \ \ \ <fieldset\ style=\"margin-left:\ 20px\;\ margin-top:\ 10px\">\n\ \ \ \ \ \ \ \ \ \ <legend>Select\ resolution:</legend>\n\ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ resolution\ \$resolutions\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"mode\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <span\ class=\"resolution\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-resolution=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"cameraResolutionClicked.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$\{resolution(width)\}x\$\{resolution(height)\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </span>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ framerate\ \$resolution(framerates)\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"camera-framerate-\$cameraId\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$(\[info\ exists\ usingOpts\]\ &&\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(width)\ ==\ \$usingOpts(width)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$resolution(height)\ ==\ \$usingOpts(height)\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$framerate\ ==\ \$usingOpts(framerate)\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"checked\"\ :\ \"\")\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"width\ \$\{resolution(width)\}\ height\ \$\{resolution(height)\}\ framerate\ \$framerate\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"cameraFramerateChange.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"%.3g\"\ \$framerate\]\ Hz\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \}\ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ </fieldset>\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \[if\ \{\$isUsingCamera\}\ \{\n\ \ \ \ \ \ \ \ \ \ set\ iframeWidth\ 600\n\ \ \ \ \ \ \ \ \ \ set\ cameraAreaHeight\ \[expr\ \{int(600.0\ *\ \$usingOpts(height)\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ set\ iframeHeight\ \[expr\ \{\$cameraAreaHeight\ +\ 48\}\]\n\ \ \ \ \ \ \ \ \ \ set\ existingCrops\ \[dict\ getdef\ \$usingOpts\ crops\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ <div\ class=\"camera-preview\"\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ relative\;\ display:\ inline-block\;\ margin-top:\ 10px\;\ line-height:\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width=\"\$iframeWidth\"\ height=\"\$iframeHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\;\ display:\ block\;\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{iframeWidth\}px\;\ height:\ \$\{cameraAreaHeight\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <!--\ \[set\ i\ 0\]\ -->\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ c\ \$existingCrops\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cx\ \[dict\ get\ \$c\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cy\ \[dict\ get\ \$c\ y\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cw\ \[dict\ get\ \$c\ width\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ch\ \[dict\ get\ \$c\ height\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rx\ \[expr\ \{int(\$cx\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ ry\ \[expr\ \{int(\$cy\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rw\ \[expr\ \{int(\$cw\ *\ \$iframeWidth\ /\ \$usingOpts(width))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ rh\ \[expr\ \{int(\$ch\ *\ \$cameraAreaHeight\ /\ \$usingOpts(height))\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-box\"\ data-index=\"\$i\"\ data-crop=\"\$cx,\$cy,\$cw,\$ch\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"left:\ \$\{rx\}px\;\ top:\ \$\{ry\}px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ \$\{rw\}px\;\ height:\ \$\{rh\}px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"nw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"ne\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"sw\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <div\ class=\"crop-handle\"\ data-corner=\"se\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cropHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \\n\]\n\ \ \ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \ \ </div>\n\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"margin-top:\ 10px\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ <button\ data-camera=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onclick=\"createVirtualCroppedCamera.call(this,\ event)\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ Create\ virtual\ cropped\ camera\n\ \ \ \ \ \ \ \ \ \ \ \ </button>\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \}\}\]\n\ \ <script>\n\ \ \ \ function\ cameraEnabledChange(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.value\;\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\n\ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ '',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraResolutionClicked(event)\ \{\n\ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ const\ firstFramerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]`\ +\n\ \ \ \ \ \ \ \ `\\\[value^=\"\\\$\{this.dataset.resolution\}\"\]`\n\ \ \ \ \ \ )\;\n\ \ \ \ \ \ firstFramerateRadio.checked\ =\ true\;\n\ \ \ \ \ \ firstFramerateRadio.dispatchEvent(new\ Event('change'))\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ function\ cameraFramerateChange(event)\ \{\n\ \ \ \ \ \ if\ (this.checked)\ \{\n\ \ \ \ \ \ \ \ const\ camera\ =\ this.dataset.camera\;\n\ \ \ \ \ \ \ \ const\ format\ =\ this.value\;\n\ \ \ \ \ \ \ \ folk.hold(`camera\ \\\$\{camera\}`,\ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{camera\}\"\ with\ \\\$\{format\}`,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\ \ \ \ const\ CROP_MCU\ =\ 16\;\n\ \ \ \ const\ snap\ =\ v\ =>\ Math.floor(v\ /\ CROP_MCU)\ *\ CROP_MCU\;\n\n\ \ \ \ function\ getCropContext(el)\ \{\n\ \ \ \ \ \ let\ preview\ =\ el.closest('.camera-preview')\;\n\ \ \ \ \ \ const\ camera\ =\ preview\ ?\ preview.dataset.camera\ :\ el.dataset.camera\;\;\n\ \ \ \ \ \ if\ (!preview)\ \{\n\ \ \ \ \ \ \ \ preview\ =\ document.querySelector(`.camera-preview\\\[data-camera=\"\\\$\{camera\}\"\]`)\;\n\ \ \ \ \ \ \}\n\n\ \ \ \ \ \ const\ iframe\ =\ preview.querySelector('iframe')\;\n\ \ \ \ \ \ const\ overlay\ =\ preview.querySelector('.crop-overlay')\;\n\ \ \ \ \ \ const\ framerateRadio\ =\ document.querySelector(\n\ \ \ \ \ \ \ \ `input\\\[type=\"radio\"\\\]\\\[name^=\"camera-framerate-\"\\\]\\\[data-camera=\"\\\$\{camera\}\"\]:checked`)\;\n\ \ \ \ \ \ if\ (!framerateRadio)\ return\ null\;\n\ \ \ \ \ \ const\ format\ =\ framerateRadio.value\;\n\ \ \ \ \ \ const\ m\ =\ format.match(/width\ (\\\\d+)\ height\ (\\\\d+)/)\;\n\ \ \ \ \ \ if\ (!m)\ return\ null\;\n\ \ \ \ \ \ return\ \{\n\ \ \ \ \ \ \ \ camera,\ preview,\ iframe,\ overlay,\ format,\n\ \ \ \ \ \ \ \ sourceWidth:\ parseInt(m\\\[1\]),\n\ \ \ \ \ \ \ \ sourceHeight:\ parseInt(m\\\[2\]),\n\ \ \ \ \ \ \ \ iframeWidth:\ parseInt(iframe.width),\n\ \ \ \ \ \ \ \ canvasHeight:\ parseInt(iframe.height)\ -\ 48,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \}\n\n\ \ \ \ function\ issueCrops(ctx,\ crops)\ \{\n\ \ \ \ \ \ const\ cropsTcl\ =\ crops\n\ \ \ \ \ \ \ \ .map((\\\[x,y,w,h\])\ =>\ `\{x\ \\\$\{x\}\ y\ \\\$\{y\}\ width\ \\\$\{w\}\ height\ \\\$\{h\}\}`)\n\ \ \ \ \ \ \ \ .join('\ ')\;\n\ \ \ \ \ \ folk.hold(`camera\ \\\$\{ctx.camera\}`,\n\ \ \ \ \ \ \ \ `Wish\ \\\$::thisNode\ uses\ camera\ \"\\\$\{ctx.camera\}\"\ with\ \\\$\{ctx.format\}\ crops\ \{\\\$\{cropsTcl\}\}`,\n\ \ \ \ \ \ \ \ 'builtin-programs/web/setup.folk',\ true)\;\n\ \ \ \ \}\n\n\ \ \ \ function\ readCrops(overlay)\ \{\n\ \ \ \ \ \ return\ Array.from(overlay.querySelectorAll('.crop-box'))\n\ \ \ \ \ \ \ \ .map(el\ =>\ el.dataset.crop.split(',').map(Number))\;\n\ \ \ \ \}\n\n\ \ \ \ function\ applyBoxStyle(ctx,\ box,\ x,\ y,\ w,\ h)\ \{\n\ \ \ \ \ \ box.style.left\ =\ (x\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.top\ =\ (y\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.width\ =\ (w\ *\ ctx.iframeWidth\ /\ ctx.sourceWidth)\ +\ 'px'\;\n\ \ \ \ \ \ box.style.height\ =\ (h\ *\ ctx.canvasHeight\ /\ ctx.sourceHeight)\ +\ 'px'\;\n\ \ \ \ \}\n\n\ \ \ \ function\ createVirtualCroppedCamera(event)\ \{\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(this)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ //\ Default:\ ~1/3\ of\ source,\ centered,\ MCU-aligned.\n\ \ \ \ \ \ const\ w\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceWidth\ /\ 3))\;\n\ \ \ \ \ \ const\ h\ =\ Math.max(CROP_MCU,\ snap(ctx.sourceHeight\ /\ 3))\;\n\ \ \ \ \ \ const\ x\ =\ snap((ctx.sourceWidth\ -\ w)\ /\ 2)\;\n\ \ \ \ \ \ const\ y\ =\ snap((ctx.sourceHeight\ -\ h)\ /\ 2)\;\n\ \ \ \ \ \ const\ crops\ =\ readCrops(ctx.overlay)\;\n\ \ \ \ \ \ crops.push(\\\[x,\ y,\ w,\ h\])\;\n\ \ \ \ \ \ issueCrops(ctx,\ crops)\;\n\ \ \ \ \ \ event.preventDefault()\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Drag\ to\ move\ (crop-box\ body)\ or\ resize\ (crop-handle\ corners).\n\ \ \ \ //\ During\ drag\ the\ overlay\ flips\ to\ pointer-events:\ auto\ so\ the\ iframe\n\ \ \ \ //\ underneath\ doesn't\ steal\ mousemove\ events\ when\ the\ cursor\ passes\n\ \ \ \ //\ over\ it.\n\ \ \ \ let\ cropDrag\ =\ null\;\n\ \ \ \ document.addEventListener('mousedown',\ e\ =>\ \{\n\ \ \ \ \ \ const\ handle\ =\ e.target.closest('.crop-handle')\;\n\ \ \ \ \ \ const\ box\ =\ e.target.closest('.crop-box')\;\n\ \ \ \ \ \ if\ (!box)\ return\;\n\ \ \ \ \ \ const\ ctx\ =\ getCropContext(box)\;\n\ \ \ \ \ \ if\ (!ctx)\ return\;\n\ \ \ \ \ \ const\ \\\[x0,\ y0,\ w0,\ h0\]\ =\ box.dataset.crop.split(',').map(Number)\;\n\ \ \ \ \ \ const\ mode\ =\ handle\ ?\ 'resize'\ :\ 'move'\;\n\ \ \ \ \ \ const\ corner\ =\ handle\ ?\ handle.dataset.corner\ :\ null\;\n\ \ \ \ \ \ cropDrag\ =\ \{\n\ \ \ \ \ \ \ \ ctx,\ box,\ mode,\ corner,\n\ \ \ \ \ \ \ \ sx:\ e.clientX,\ sy:\ e.clientY,\n\ \ \ \ \ \ \ \ x0,\ y0,\ w0,\ h0,\n\ \ \ \ \ \ \ \ live:\ null,\n\ \ \ \ \ \ \}\;\n\ \ \ \ \ \ ctx.overlay.style.pointerEvents\ =\ 'auto'\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ mode\ ===\ 'move'\ ?\ 'move'\n\ \ \ \ \ \ \ \ :\ (corner\ ===\ 'nw'\ ||\ corner\ ===\ 'se')\ ?\ 'nwse-resize'\n\ \ \ \ \ \ \ \ :\ 'nesw-resize'\;\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ e.stopPropagation()\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mousemove',\ e\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ const\ dx\ =\ (e.clientX\ -\ d.sx)\ *\ (d.ctx.sourceWidth\ /\ d.ctx.iframeWidth)\;\n\ \ \ \ \ \ const\ dy\ =\ (e.clientY\ -\ d.sy)\ *\ (d.ctx.sourceHeight\ /\ d.ctx.canvasHeight)\;\n\ \ \ \ \ \ let\ x,\ y,\ w,\ h\;\n\ \ \ \ \ \ if\ (d.mode\ ===\ 'move')\ \{\n\ \ \ \ \ \ \ \ x\ =\ Math.max(0,\ Math.min(d.ctx.sourceWidth\ -\ d.w0,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ y\ =\ Math.max(0,\ Math.min(d.ctx.sourceHeight\ -\ d.h0,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ w\ =\ d.w0\;\ h\ =\ d.h0\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ let\ left\ =\ d.x0,\ top\ =\ d.y0\;\n\ \ \ \ \ \ \ \ let\ right\ =\ d.x0\ +\ d.w0,\ bottom\ =\ d.y0\ +\ d.h0\;\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('w'))\ \{\n\ \ \ \ \ \ \ \ \ \ left\ =\ Math.max(0,\ Math.min(right\ -\ CROP_MCU,\ snap(d.x0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('e'))\ \{\n\ \ \ \ \ \ \ \ \ \ right\ =\ Math.max(left\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceWidth,\ snap(d.x0\ +\ d.w0\ +\ dx)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('n'))\ \{\n\ \ \ \ \ \ \ \ \ \ top\ =\ Math.max(0,\ Math.min(bottom\ -\ CROP_MCU,\ snap(d.y0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ (d.corner.includes('s'))\ \{\n\ \ \ \ \ \ \ \ \ \ bottom\ =\ Math.max(top\ +\ CROP_MCU,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Math.min(d.ctx.sourceHeight,\ snap(d.y0\ +\ d.h0\ +\ dy)))\;\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ x\ =\ left\;\ y\ =\ top\;\ w\ =\ right\ -\ left\;\ h\ =\ bottom\ -\ top\;\n\ \ \ \ \ \ \}\n\ \ \ \ \ \ d.live\ =\ \\\[x,\ y,\ w,\ h\]\;\n\ \ \ \ \ \ applyBoxStyle(d.ctx,\ d.box,\ x,\ y,\ w,\ h)\;\n\ \ \ \ \})\;\n\ \ \ \ document.addEventListener('mouseup',\ ()\ =>\ \{\n\ \ \ \ \ \ const\ d\ =\ cropDrag\;\n\ \ \ \ \ \ if\ (!d)\ return\;\n\ \ \ \ \ \ cropDrag\ =\ null\;\n\ \ \ \ \ \ d.ctx.overlay.style.pointerEvents\ =\ ''\;\n\ \ \ \ \ \ document.body.style.cursor\ =\ ''\;\n\ \ \ \ \ \ if\ (!d.live)\ return\;\n\ \ \ \ \ \ d.box.dataset.crop\ =\ d.live.join(',')\;\n\ \ \ \ \ \ issueCrops(d.ctx,\ readCrops(d.ctx.overlay))\;\n\ \ \ \ \})\;\n\ \ </script>\n</div>\n\n<div>\n\ \ <h2>Projector-camera\ calibration</h2>\n\ \ <p>Select\ <strong>one\ display</strong>\ and\ <strong>one\ or\ more\ cameras</strong>\ to\ calibrate:</p>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Display\ (projector)</strong></legend>\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ display\ /display/\ with\ /...opts/\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"radio\"\ name=\"calibration-display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$display\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$display\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <fieldset\ style=\"margin:\ 10px\ 0\;\ border:\ 1px\ solid\ #ccc\;\ padding:\ 10px\;\">\n\ \ \ \ <legend><strong>Cameras</strong></legend>\n\ \ \ \ <!--\ \[fn\ emitCameraHtml\ \{camera\}\ \{\n\ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ <div\ style=\"margin:\ 5px\ 0\;\">\n\ \ \ \ \ \ \ \ \ \ <label>\n\ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"checkbox\"\ name=\"calibration-camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ value=\"\$camera\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onchange=\"calibrationSelectionChange()\">\n\ \ \ \ \ \ \ \ \ \ \ \ \$camera\n\ \ \ \ \ \ \ \ \ \ </label>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \}\n\ \ \ \ \}\]\ -->\n\ \ \ \ \[HtmlWhen\ /someone/\ wishes\ \$::thisNode\ uses\ camera\ /camera/\ with\ /...opts/\ \{\n\ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$opts\ crops\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ htmls\ \[list\]\n\ \ \ \ \ \ \ \ \ \ \ \ loop\ i\ \[llength\ \$opts(crops)\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ htmls\ \[emitCameraHtml\ \[list\ \$camera\ \$i\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ join\ \$htmls\ \\n\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitCameraHtml\ \$camera\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\]\n\ \ </fieldset>\n\n\ \ <button\ id=\"calibrate-button\"\ disabled\ onclick=\"startCalibration()\">Calibrate</button>\n\n\ \ <script>\n\ \ \ \ function\ calibrationSelectionChange()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked')\;\n\ \ \ \ \ \ const\ button\ =\ document.getElementById('calibrate-button')\;\n\ \ \ \ \ \ button.disabled\ =\ !display\ ||\ cameras.length\ ===\ 0\;\n\ \ \ \ \}\n\n\ \ \ \ function\ startCalibration()\ \{\n\ \ \ \ \ \ const\ display\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]:checked')\;\n\ \ \ \ \ \ const\ cameras\ =\ Array.from(document.querySelectorAll('input\\\[name=\"calibration-camera\"\]:checked'))\;\n\n\ \ \ \ \ \ if\ (!display\ ||\ cameras.length\ ===\ 0)\ return\;\n\n\ \ \ \ \ \ const\ params\ =\ new\ URLSearchParams()\;\n\ \ \ \ \ \ params.append('display',\ display.value)\;\n\ \ \ \ \ \ cameras.forEach(camera\ =>\ params.append('camera',\ camera.value))\;\n\n\ \ \ \ \ \ window.location.href\ =\ `/calibrate?\\\$\{params.toString()\}`\;\n\ \ \ \ \}\n\n\ \ \ \ const\ firstDisplay\ =\ document.querySelector('input\\\[name=\"calibration-display\"\]')\;\n\ \ \ \ if\ (firstDisplay)\ firstDisplay.checked\ =\ true\;\n\ \ \ \ const\ firstCamera\ =\ document.querySelector('input\\\[name=\"calibration-camera\"\]')\;\n\ \ \ \ if\ (firstCamera)\ firstCamera.checked\ =\ true\;\n\ \ \ \ calibrationSelectionChange()\;\n\ \ </script>\n</div>\n\n</body>\n</html>\n\}\]\n {{this builtin-programs/web/setup.folk} {} {}}}
builtin-programs/web/program.folk wishes the web server handles route {/program/(.*)$} with handler { (
[ m538:0 () ]
)builtin-programs/web/program.folk wishes the web server handles route {/program/(.*)$} with handler {applyBlock {
set programName $1
Expect! $1 has program code /programCode/
html [subst {
<html>
<head>
<title>[htmlEscape $programName]</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>[htmlEscape $programName]</h1>
<pre><code>[htmlEscape $programCode]</code></pre>
</body>
</html>
}]
} {{this builtin-programs/web/program.folk} {} {}}}
builtin-programs/web/quads.folk wishes the web server handles route /quads with handler {applyBlock { (
[ m570:0 () ]
)builtin-programs/web/quads.folk wishes the web server handles route /quads with handler {applyBlock {
html {
<!DOCTYPE html>
<html>
<head>
<title>Folk Quads 3D</title>
<script src="/lib/folk.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
}
}
</script>
<style>
body {
margin: 0;
overflow: hidden;
font-family: monospace;
}
#canvas-container {
width: 100vw;
height: 100vh;
}
#stats {
position: absolute;
top: 10px;
left: 10px;
color: white;
background: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 4px;
font-size: 14px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="stats">
<div>Quads: <span id="quad-count">0</span></div>
<div>Space: <span id="camera-space">none</span></div>
</div>
<div id="canvas-container"></div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Initialize scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a1a);
// Initialize camera
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.01,
100
);
camera.position.set(0, 0, -2);
camera.lookAt(0, 0, 0);
// Initialize renderer
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Initialize controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 0.1;
controls.maxDistance = 10;
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4);
directionalLight.position.set(1, 2, 1);
scene.add(directionalLight);
// Add grid helper (2m x 2m, 20 divisions = 10cm each)
const gridHelper = new THREE.GridHelper(2, 20);
scene.add(gridHelper);
// Add axes helper (0.5m)
const axesHelper = new THREE.AxesHelper(0.5);
scene.add(axesHelper);
// State management
const quadMeshes = new Map(); // tag -> { mesh, sprite }
let firstCameraSpace = null;
window.allQuads = [];
// Color generation
function getColorForTag(tag) {
const hash = Math.abs(tag.split('').reduce((h, c) =>
((h << 5) - h) + c.charCodeAt(0), 0));
const hue = (hash % 360) / 360;
return new THREE.Color().setHSL(hue, 0.7, 0.6);
}
// Compute centroid + normal offset for a quad's
// vertices so the label sprite sits slightly above
// the surface (label has smaller Z value) instead of
// coplanar.
function quadLabelPosition(vertices) {
const centroid = vertices.reduce(
(sum, v) => [sum[0] + v[0]/4, sum[1] + v[1]/4, sum[2] + v[2]/4],
[0, 0, 0]);
const v0 = new THREE.Vector3(...vertices[0]);
const v1 = new THREE.Vector3(...vertices[1]);
const v3 = new THREE.Vector3(...vertices[3]);
const normal = new THREE.Vector3()
.crossVectors(
new THREE.Vector3().subVectors(v1, v0),
new THREE.Vector3().subVectors(v3, v0))
.normalize();
return new THREE.Vector3(...centroid).addScaledVector(normal, -0.005);
}
// Create quad mesh from vertices
function createQuadMesh(tag, vertices) {
const geometry = new THREE.BufferGeometry();
// vertices: [TL, TR, BR, BL]
// Create two triangles: [TL, TR, BL] and [TR, BR, BL]
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.computeVertexNormals();
const color = getColorForTag(tag);
const material = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.8
});
return new THREE.Mesh(geometry, material);
}
// Create label sprite
function createLabelSprite(text) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 128;
context.font = 'Bold 48px Arial';
context.fillStyle = 'white';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, 256, 64);
const texture = new THREE.CanvasTexture(canvas);
const material = new THREE.SpriteMaterial({ map: texture, depthTest: false });
const sprite = new THREE.Sprite(material);
sprite.scale.set(0.2, 0.05, 1);
return sprite;
}
// Update statistics display
function updateStatistics(count, space) {
document.getElementById('quad-count').textContent = count;
document.getElementById('camera-space').textContent = space || 'none';
}
// Update quads in the scene
function updateQuads() {
// Filter quads by camera space
const filtered = firstCameraSpace
? window.allQuads.filter(r => r.quad && r.quad[0] === firstCameraSpace)
: window.allQuads;
const currentTags = new Set(filtered.map(r => r.tag));
// Remove deleted quads
for (const [tag, objects] of quadMeshes.entries()) {
if (!currentTags.has(tag)) {
scene.remove(objects.mesh);
scene.remove(objects.sprite);
quadMeshes.delete(tag);
}
}
// Add or update quads
for (const result of filtered) {
const { tag, quad } = result;
if (!quad || quad.length < 2) continue;
const [space, vertices] = quad;
if (!vertices || vertices.length !== 4) continue;
const verticesKey = JSON.stringify(vertices);
if (!quadMeshes.has(tag)) {
const mesh = createQuadMesh(tag, vertices);
const sprite = createLabelSprite(tag);
sprite.position.copy(quadLabelPosition(vertices));
scene.add(mesh);
scene.add(sprite);
quadMeshes.set(tag, { mesh, sprite, verticesKey });
} else {
// Check if vertices changed
const objects = quadMeshes.get(tag);
if (objects.verticesKey !== verticesKey) {
// Update mesh geometry
const positions = new Float32Array([
...vertices[0], ...vertices[1], ...vertices[3], // Triangle 1
...vertices[1], ...vertices[2], ...vertices[3] // Triangle 2
]);
objects.mesh.geometry.setAttribute('position',
new THREE.BufferAttribute(positions, 3));
objects.mesh.geometry.computeVertexNormals();
// Update sprite position
objects.sprite.position.copy(quadLabelPosition(vertices));
// Update stored vertices key
objects.verticesKey = verticesKey;
}
}
}
updateStatistics(quadMeshes.size, firstCameraSpace);
}
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
animate();
// Connect to Folk
const ws = new FolkWS();
// Watch for camera space
ws.watchCollected("/someone/ claims camera /camera/ has width /w/ height /h/",
results => {
const newSpace = results[0]?.camera || null;
if (newSpace !== firstCameraSpace) {
firstCameraSpace = newSpace;
updateQuads();
}
}
);
// Watch for quads
ws.watchCollected("/someone/ claims /tag/ has quad /quad/", results => {
allQuads = results.map(r => {
const r1 = {...r};
r1.quad = loadList(r.quad);
r1.quad[1] = loadList(r1.quad[1]).map(row => loadList(row));
return r1;
});
updateQuads();
});
</script>
</body>
</html>
}
} {{this builtin-programs/web/quads.folk} {} {}}}
builtin-programs/web/keyboards.folk wishes the web server handles route {/keyboards$} with handler {a (
[ m576:0 () ]
)builtin-programs/web/keyboards.folk wishes the web server handles route {/keyboards$} with handler {applyBlock {
set keyboards [lmap result [Query! /someone/ claims /keyboard/ is a keyboard device] {
dict get $result keyboard
}]
html [subst {
<html>
<head>
<style>
body {
background-color: #222;
color: whitesmoke;
}
.kbinfo {
outline: 1px solid whitesmoke;
border-radius: 6px;
font-family: monospace;
margin: 1%;
padding: 1%;
}
.path:before {
content: "Path: "
}
</style>
</head>
<body>
<span id="status">Status</span>
<dl>
[join [lmap kb $keyboards { subst {
<div class=kbinfo>
<dt class=path>$kb</dt>
<dd>
<span>Keys typed: </span><code id="$kb-presses"></code>
</dd>
<dd>
<button onclick="handlePrint('$kb')">Print</button>
</dd>
</div>
} }] "\n"]
</dl>
<script src="/lib/folk.js"></script>
<script>
const ws = new FolkWS(document.getElementById('status'));
ws.subscribe("keyboard /kb/ claims key /anything/ is down with /...options/", ({ kb, options }) => {
const { printable } = loadDict(options);
document.getElementById(kb + "-presses").innerText += printable + " ";
});
function handlePrint(kb) {
ws.send(
tcl`Notify: print code {Claim \$this is a keyboard with path \${kb}}`
);
}
</script>
</body>
</html>
}]
} {{this builtin-programs/web/keyboards.folk} {} {}}}
builtin-programs/web/page.folk wishes the web server handles route {/page/(.*)$} with handler {applyB (
[ m591:0 () ]
)builtin-programs/web/page.folk wishes the web server handles route {/page/(.*)$} with handler {applyBlock \n\ \ \ \ Expect!\ the\ program\ save\ directory\ is\ /programDir/\n\ \ \ \ set\ program_id\ \$1\n\ \ \ \ set\ filenames\ \[list\ \\\n\ \ \ \ \ \ \ \ \"\$programDir/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"\$::env(HOME)/folk-live/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"user-programs/\[info\ hostname\]/\$program_id.folk\"\ \\\n\ \ \ \ \ \ \ \ \"builtin-programs/\$program_id.folk\"\ \\\n\ \ \ \ \]\n\n\ \ \ \ foreach\ filename\ \$filenames\ \{\n\ \ \ \ \ \ \ \ if\ \[file\ exists\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ file_data\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ if\ \{!\[info\ exists\ file_data\]\}\ \{\n\ \ \ \ \ \ \ \ set\ filename\ \[lindex\ \$filenames\ end\]\n\ \ \ \ \ \ \ \ set\ file_data\ \"#\ (new\ file\ \$filename)\"\n\ \ \ \ \}\n\n\ \ \ \ html\ \[string\ map\ \[list\ file_data\ \[htmlEscape\ \$file_data\]\ program_id\ \$program_id\ file_name\ \$filename\]\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <div>\n\ \ \ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ \ \ <button\ id=\"print\"\ onclick=\"handlePrint()\">Print</button>\n\ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ <textarea\ id=\"code\"\ style=\"width:\ 100%\;height:\ 95vh\;\">file_data</textarea>\n\ \ \ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ const\ isVirtualProgram\ =\ !'file_name'.includes('folk-printed-programs')\;\n\n\ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ document.getElementById(\"print\").disabled\ =\ true\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ \ \ \ \ \ \ \ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handleSave()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\ \ \ \ \ \ \ \ \ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ \ \ \ \ \ \ \ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \},\ false)\;\n\n\ \ \ \ \ \ \ \ \ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ \ ws.watchCollected(tcl`program_id\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ e.errorInfo).join('\\n')\;\n\ \ \ \ \ \ \ \ \ \ \})\;\n\n\ \ \ \ \ \ \ \ \ \ function\ handleSave()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fp\ \[open\ file_name\ w\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ -nonewline\ \$fp\ \$\{code\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Saved\ program_id.folk\"\n\ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (isVirtualProgram)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`EditVirtualProgram\ file_name\ \$\{code\}`)\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ let\ jobid\;\n\ \ \ \ \ \ \ \ \ \ function\ handlePrint()\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ \ \ \ \ \ \ \ \ jobid\ =\ String(Math.random())\;\n\ \ \ \ \ \ \ \ \ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/page.folk} {} {}}}
builtin-programs/web/new.folk wishes the web server handles route /new with nav {<button>New program< (
[ m605:0 () ]
)builtin-programs/web/new.folk wishes the web server handles route /new with nav {<button>New program</button>} handler {applyBlock \n\ \ \ \ html\ \{\n<html\ lang=\"en\">\n\ \ <head>\n\ \ \ \ <meta\ charset=\"UTF-8\">\n\ \ \ \ <meta\ name=\"viewport\"\ content=\"width=device-width,\ initial-scale=1.0\">\n\ \ \ \ <style>\n\ \ \ \ \ \ \ \ body\ \{\ overflow:\ hidden\;\ \}\n\ \ \ \ </style>\n\ \ </head>\n\ \ <body>\n\ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ <div\ id=\"dragme\"\ style=\"cursor:\ move\;\ position:\ absolute\;\ user-select:\ none\;\ background-color:\ #ccc\;\ padding:\ 1em\">\n\ \ \ \ \ \ <textarea\ id=\"code\"\ cols=\"50\"\ rows=\"20\"\ style=\"font-family:\ monospace\">Wish\ \$this\ is\ outlined\ blue</textarea>\n\ \ \ \ \ \ <p>\n\ \ \ \ \ \ \ \ <button\ onclick=\"handleSave()\">Save</button>\n\ \ \ \ \ \ \ \ <button\ id=\"printBtn\"\ onclick=\"handlePrint()\">Print</button>\n\n\ \ \ \ \ \ \ \ <input\ id=\"regionAngleRange\"\ type=\"range\"\ value=\"0\"\ min=\"0\"\ max=\"360\"\ step=\"0.1\"\ oninput=\"this.nextElementSibling.value\ =\ `angle:\ \$\{this.value\}°\;`\;\ regionAngle\ =\ this.value\;\ handleDrag()\;\">\n\ \ \ \ \ \ \ \ <output>angle:\ 0°\;</output>\n\ \ \ \ \ \ </p>\n\ \ \ \ \ \ <pre\ id=\"error\"></pre>\n\ \ \ \ </div>\n\n\ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ <script>\n\ \ //\ The\ current\ position\ of\ mouse\n\ \ let\ x\ =\ 0\;\n\ \ let\ y\ =\ 0\;\n\n\ \ //\ Query\ the\ element\n\ \ const\ ele\ =\ document.getElementById('dragme')\;\n\ \ const\ codeEle\ =\ document.getElementById(\"code\")\;\n\ \ const\ angleEle\ =\ document.getElementById(\"regionAngleRange\")\;\n\ \ const\ errorEle\ =\ document.getElementById(\"error\")\;\n\ \ \n\n\ \ //\ Handle\ the\ mousedown\ event\n\ \ //\ that's\ triggered\ when\ user\ drags\ the\ element\n\ \ const\ mouseDownHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\ \ \ \ if\ (e.target\ ==\ angleEle)\ return\;\n\n\ \ \ \ //\ Get\ the\ current\ mouse\ position\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\n\ \ \ \ //\ Attach\ the\ listeners\ to\ `document`\n\ \ \ \ document.addEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.addEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ const\ mouseMoveHandler\ =\ function\ (e)\ \{\n\ \ \ \ if\ (e.target\ ==\ codeEle)\ return\;\n\n\ \ \ \ //\ How\ far\ the\ mouse\ has\ been\ moved\n\ \ \ \ const\ dx\ =\ e.clientX\ -\ x\;\n\ \ \ \ const\ dy\ =\ e.clientY\ -\ y\;\n\n\ \ \ \ //\ Set\ the\ position\ of\ element\n\ \ \ \ const\ \[top,\ left\]\ =\ \[ele.offsetTop\ +\ dy,\ ele.offsetLeft\ +\ dx\]\;\n\ \ \ \ ele.style.top\ =\ `\$\{top\}px`\;\n\ \ \ \ ele.style.left\ =\ `\$\{left\}px`\;\n\ \ \ \ handleDrag()\;\n\n\ \ \ \ //\ Reassign\ the\ position\ of\ mouse\n\ \ \ \ x\ =\ e.clientX\;\n\ \ \ \ y\ =\ e.clientY\;\n\ \ \}\;\n\n\ \ const\ mouseUpHandler\ =\ function\ ()\ \{\n\ \ \ \ //\ Remove\ the\ handlers\ of\ `mousemove`\ and\ `mouseup`\n\ \ \ \ document.removeEventListener('pointermove',\ mouseMoveHandler)\;\n\ \ \ \ document.removeEventListener('pointerup',\ mouseUpHandler)\;\n\ \ \}\;\n\n\ \ //\ Cmd\ +\ S\ ||\ Ctrl\ +\ S\ =>\ Save\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 83)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handleSave()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\ \ //\ Cmd\ +\ P\ ||\ Ctrl\ +\ P\ =>\ Print\n\ \ document.addEventListener('keydown',\ function(e)\ \{\n\ \ \ \ if\ ((window.navigator.platform.match('Mac')\ ?\ e.metaKey\ :\ e.ctrlKey)\ \ &&\ e.keyCode\ ==\ 80)\ \{\n\ \ \ \ \ \ e.preventDefault()\;\n\ \ \ \ \ \ handlePrint()\;\n\ \ \ \ \}\n\ \ \},\ false)\;\n\n\ \ ele.addEventListener('pointerdown',\ mouseDownHandler)\;\n\n\ \ function\ uuidv4()\ \{\n\ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ )\;\n\ \ \ \ \}\n\ \ const\ program\ =\ \"web-program-\"\ +\ uuidv4()\;\n\n\ \ let\ regionAngle\ =\ 0\;\n\ \ const\ ws\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ ws.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ canv\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ geom\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ quad\ \{\}\n\ \ \ \ \ \ Hold!\ -on\ \$this\ -key\ code\ \{\}\n\ \ \ \ \}\n\ \ `)\;\n\n\ \ ws.hold('canv',\ tcl`\n\ \ \ \ Wish\ \$\{program\}\ has\ a\ canvas\n\ \ `)\;\n\n\ \ function\ formatErrorInfo(errorInfoDict)\ \{\n\ \ \ \ errorInfoDict\ =\ loadDict(errorInfoDict)\;\n\ \ \ \ const\ stacktrace\ =\ errorInfoDict\['-errorinfo'\]\;\n\n\ \ \ \ //\ Parse\ the\ stacktrace\ list\ (simplified\ Tcl\ list\ parser)\n\ \ \ \ //\ Format:\ \[proc\ file\ line\ cmd\ proc\ file\ line\ cmd\ ...\]\n\ \ \ \ const\ frames\ =\ \[\]\;\n\ \ \ \ const\ tokens\ =\ loadList(stacktrace)\;\n\n\ \ \ \ //\ Group\ tokens\ into\ frames\ of\ 4:\ proc,\ file,\ line,\ cmd\n\ \ \ \ for\ (let\ i\ =\ 0\;\ i\ +\ 3\ <\ tokens.length\;\ i\ +=\ 4)\ \{\n\ \ \ \ \ \ const\ \[proc,\ file,\ line,\ cmd\]\ =\ tokens.slice(i,\ i\ +\ 4)\;\n\ \ \ \ \ \ frames.push(\{\ proc,\ file,\ line,\ cmd\ \})\;\n\ \ \ \ \}\n\n\ \ \ \ if\ (frames.length\ ===\ 0)\ return\ errorInfoDict\;\n\n\ \ \ \ //\ Format\ like\ Jim's\ errorInfo:\ \"file:line:\ Error:\ msg\\nstackdump\"\n\ \ \ \ const\ firstFrame\ =\ frames\[0\]\;\n\ \ \ \ let\ result\ =\ \"\"\;\n\n\ \ \ \ if\ (firstFrame.file\ &&\ firstFrame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ result\ =\ `\$\{firstFrame.file\}:\$\{firstFrame.line\}:\ Error:\ `\;\n\ \ \ \ \}\n\n\ \ \ \ //\ Extract\ error\ message\ (usually\ in\ the\ cmd\ of\ first\ frame)\n\ \ \ \ result\ +=\ `\$\{firstFrame.cmd\}\\n`\;\n\n\ \ \ \ //\ Add\ stackdump\n\ \ \ \ for\ (const\ frame\ of\ frames)\ \{\n\ \ \ \ \ \ if\ (frame.file\ &&\ frame.file\ !==\ \"\")\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\ called\ at\ \$\{frame.file\}:\$\{frame.line\}\\n`\;\n\ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ result\ +=\ `in\ \$\{frame.proc\}\\n`\;\n\ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ return\ result.trim()\;\n\ \ \}\n\n\ \ ws.watchCollected(tcl`\$\{program\}\ has\ error\ /something/\ with\ info\ /errorInfo/`,\ errors\ =>\ \{\n\ \ \ \ errorEle.style.backgroundColor\ =\ errors.length\ ?\ \"#f55\"\ :\ \"\"\;\n\ \ \ \ errorEle.innerText\ =\ errors.map(e\ =>\ formatErrorInfo(e.errorInfo)).join('\\n')\;\n\ \ \})\;\n\n\ \ function\ handleDrag()\ \{\n\ \ \ \ let\ \[top,\ left,\ w,\ h\]\ =\ \[ele.offsetTop,\ ele.offsetLeft,\ ele.offsetWidth,\ ele.offsetHeight\]\;\n\ \ \ \ ws.hold('geom',\ tcl`\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ resolved\ geometry\ \{width\ \$\{w\ /\ 2000\}\ height\ \$\{h\ /\ 2000\}\}\n\ \ \ `)\;\n\ \ \ \ ws.hold('quad',\ tcl`\n\ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::sub\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::matmul\n\ \ \ \ \ \ namespace\ import\ ::math::linearalgebra::scale\n\n\ \ \ \ \ \ Expect!\ the\ quad\ library\ is\ /quadLib/\n\ \ \ \ \ \ Expect!\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\n\n\ \ \ \ \ \ set\ x\ \[expr\ \{int(double(\$\{(left\ +\ (left/window.innerWidth)\ *\ w)\})\ *\ (double(\$displayWidth)\ /\ \$\{window.innerWidth\}))\}\]\n\ \ \ \ \ \ set\ y\ \[expr\ \{int(double(\$\{(top\ +\ (top/window.innerHeight)\ *\ h)\})\ *\ (double(\$displayHeight)\ /\ \$\{window.innerHeight\}))\}\]\n\ \ \ \ \ \ set\ w\ \$\{w\}\;\ set\ h\ \$\{h\}\n\n\ \ \ \ \ \ #\ Create\ 3D\ vertices\ in\ meters\ that\ will\ project\ to\ the\ desired\ pixel\ coordinates\n\ \ \ \ \ \ #\ Using\ a\ depth\ of\ 1.5\ meters\ from\ the\ projector\ center\n\ \ \ \ \ \ set\ depth\ 1.5\n\ \ \ \ \ \ Expect!\ display\ \$disp\ has\ intrinsics\ /displayIntrinsics/\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ pixel\ coordinates\ to\ 3D\ coordinates\ in\ projector\ space\n\ \ \ \ \ \ set\ fx\ \[dict\ get\ \$displayIntrinsics\ fx\]\n\ \ \ \ \ \ set\ fy\ \[dict\ get\ \$displayIntrinsics\ fy\]\ \n\ \ \ \ \ \ set\ cx\ \[dict\ get\ \$displayIntrinsics\ cx\]\n\ \ \ \ \ \ set\ cy\ \[dict\ get\ \$displayIntrinsics\ cy\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Scale\ pixel\ coordinates\ to\ intrinsic\ matrix\ dimensions\n\ \ \ \ \ \ set\ scale_x\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ width\]\ /\ double(\$displayWidth)\}\]\n\ \ \ \ \ \ set\ scale_y\ \[expr\ \{\[dict\ get\ \$displayIntrinsics\ height\]\ /\ double(\$displayHeight)\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ x_scaled\ \[expr\ \{\$x\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ y_scaled\ \[expr\ \{\$y\ *\ \$scale_y\}\]\n\ \ \ \ \ \ set\ w_scaled\ \[expr\ \{\$w\ *\ \$scale_x\}\]\n\ \ \ \ \ \ set\ h_scaled\ \[expr\ \{\$h\ *\ \$scale_y\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ #\ Convert\ to\ normalized\ coordinates\ then\ to\ 3D\n\ \ \ \ \ \ set\ x1_3d\ \[expr\ \{(\$x_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y1_3d\ \[expr\ \{(\$y_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ set\ x2_3d\ \[expr\ \{(\$x_scaled\ +\ \$w_scaled\ -\ \$cx)\ *\ \$depth\ /\ \$fx\}\]\n\ \ \ \ \ \ set\ y2_3d\ \[expr\ \{(\$y_scaled\ +\ \$h_scaled\ -\ \$cy)\ *\ \$depth\ /\ \$fy\}\]\n\ \ \ \ \ \ \n\ \ \ \ \ \ set\ vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y1_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x2_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[list\ \$x1_3d\ \$y2_3d\ \$depth\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ #\ Get\ the\ angle\ (in\ radians)\ from\ JS\n\ \ \ \ \ \ set\ angle_rad\ \[expr\ \{\$\{regionAngle\}\ *\ 3.14159265\ /\ 180.0\}\]\n\n\ \ \ \ \ \ #\ Manually\ create\ the\ 3D\ rotation\ matrix\ for\ the\ Z-axis\n\ \ \ \ \ \ set\ c\ \[expr\ \{cos(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ s\ \[expr\ \{sin(\$angle_rad)\}\]\n\ \ \ \ \ \ set\ R\ \[list\ \[list\ \$c\ \[expr\ \{-1.0\ *\ \$s\}\]\ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$s\ \$c\ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.0\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ 0.0\ 0.0\ \ \ \ \ \ \ \ \ \ \ \ \ 1.0\]\]\n\n\ \ \ \ \ \ #\ Calculate\ the\ centroid\ (center)\ of\ the\ quad\n\ \ \ \ \ \ lassign\ \$vertices\ v1\ v2\ v3\ v4\n\n\ \ \ \ \ \ set\ centroid\ \[scale\ 0.25\ \[add\ \[add\ \$v1\ \$v2\]\ \[add\ \$v3\ \$v4\]\]\]\n\n\ \ \ \ \ \ #\ Rotate\ each\ vertex\ around\ the\ centroid\n\ \ \ \ \ \ #\ Formula:\ new_vertex\ =\ RotationMatrix\ *\ (vertex\ -\ centroid)\ +\ centroid\n\ \ \ \ \ \ set\ rotated_vertices\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v1\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v2\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v3\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \ \ \ \ \[add\ \[matmul\ \$R\ \[sub\ \$v4\ \$centroid\]\]\ \$centroid\]\ \\\n\ \ \ \ \ \ \]\n\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ quad\ \\\n\ \ \ \ \ \ \ \ \ \ \[\$quadLib\ create\ \"display\ \$disp\"\ \$rotated_vertices\]\n\ \ `)\;\n\ \ \}\n\ \ function\ handleSave()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ //\ base64-encoding\ the\ code\ ensures\ that\ backslash-newlines\ are\n\ \ \ \ //\ preserved\ in\ the\ code\ and\ printout\ (otherwise,\ braced-string-parsing\n\ \ \ \ //\ would\ elide\ them:\ https://www.tcl.tk/man/tcl8.7/TclCmd/Tcl.html#M10)\n\ \ \ \ ws.hold('code',\ tcl`\n\ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ Claim\ \$\{program\}\ has\ program\ code\ \[binary\ decode\ base64\ \$\{btoa(code)\}\]\n\ \ \ \ `)\;\n\ \ \}\n\ \ function\ handlePrint()\ \{\n\ \ \ \ const\ code\ =\ document.getElementById(\"code\").value\;\n\ \ \ \ const\ jobid\ =\ String(Math.random())\;\n\ \ \ \ ws.send(tcl`Notify:\ print\ code\ \$\{code\}`)\;\n\ \ \ \ let\ printBtn\ =\ document.getElementById(\"printBtn\")\n\ \ \ \ printBtn.innerText\ =\ \"Printing\"\;\n\ \ \ \ printBtn.disabled\ =\ true\;\n\ \ \ \ setTimeout(()\ =>\ \{\n\ \ \ \ \ \ printBtn.innerText\ =\ \"Print\"\;\n\ \ \ \ \ \ printBtn.disabled\ =\ false\;\n\ \ \ \ \},\ 1000)\;\n\ \ \}\n\ \ handleDrag()\;\n\ \ \ \ </script>\n\ \ </body>\n</html>\n\ \ \ \ \}\n {{this builtin-programs/web/new.folk} {} {}}}
builtin-programs/web/log.folk wishes the web server handles route {/log/(.+)$} with hidden true handl (
[ m613:0 () ]
)builtin-programs/web/log.folk wishes the web server handles route {/log/(.+)$} with hidden true handler {applyBlock {
set filename [string map {/ __} $1]
set path "/var/tmp/folk-[pid]/$filename"
set content ""
catch { set content [exec tail -c 100000 $path] }
dict create statusAndHeaders "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" body $content
} {{this builtin-programs/web/log.folk} {} {}}}
builtin-programs/web/printed-programs.folk wishes the web server handles route {/printed-programs/([^ (
[ m639:0 () ]
)builtin-programs/web/printed-programs.folk wishes the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {applyBlock {
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
close $fp
dict create statusAndHeaders "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain; charset=utf-8\n\n" body $data
} {{this builtin-programs/web/printed-programs.folk} {} {}}}
builtin-programs/web/index.folk wishes the web server handles route / with handler {applyBlock \n\ \ (
[ m647:0 () ]
)builtin-programs/web/index.folk wishes the web server handles route / with handler {applyBlock \n\ \ \ \ fn\ readOutputFile\ \{path\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{set\ fp\ \[open\ \$path\ r\]\}\]\}\ \{\ return\ \"\"\ \}\n\ \ \ \ \ \ \ \ set\ content\ \[read\ \$fp\]\n\ \ \ \ \ \ \ \ close\ \$fp\n\ \ \ \ \ \ \ \ return\ \$content\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForProgramList\ \{programList\ label\}\ \{\n\ \ \ \ \ \ \ \ set\ programList\ \[lsort\ -command\ \{apply\ \{\{a\ b\}\ \{string\ compare\ \$a(programName)\ \$b(programName)\}\}\}\ \$programList\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ map\ \{-\ \"\ \"\}\ \$label\]\n\ \ \ \ \ \ \ \ set\ prettyLabel\ \[string\ totitle\ \$prettyLabel\]:\n\ \ \ \ \ \ \ \ set\ returnList\ \[list\ \"<details\ open\ data-label='\$label'\ data-count='\[llength\ \$programList\]'><summary>\$prettyLabel\ (\[llength\ \$programList\])</summary>\"\]\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"<ul>\"\n\ \ \ \ \ \ \ \ foreach\ item\ \$programList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ escapedThis\ \[regsub\ -all\ --\ /\ \$item(programName)\ __\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ out\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stdout\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ err\ \[readOutputFile\ \"/var/tmp/folk-\[pid\]/\$escapedThis.stderr\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputHtml\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$out\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #888'>\[htmlEscape\ \$out\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$err\ ne\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$err\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outLen\ \[string\ length\ \$out\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errLen\ \[string\ length\ \$err\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$item(programName)\ ne\ \"sysmon.c\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ outputSuffix\ \"(<a\ href='/program/\$item(programName)'>source</a>)\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$outLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{outLen\}b\ stdout</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errLen\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ <span\ style='font-size:\ 0.75em\;\ color:\ #888'>\$\{errLen\}b\ stderr</span>\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errors\ \[Query!\ \$item(programName)\ has\ error\ /err/\ with\ info\ /info/\]\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ e\ \$errors\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ outputHtml\ \"<pre\ style='margin:\ 0.25em\ 0\ 0\ 1em\;\ padding:\ 0.25em\ 0.5em\;\ font-size:\ 0.85em\;\ white-space:\ pre-wrap\;\ border-left:\ 3px\ solid\ #c00\;\ color:\ #c00'>\[htmlEscape\ \$e(err)\]</pre>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ errCount\ \[llength\ \$errors\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ displayName\ \[regsub\ \{^builtin-programs/\}\ \$item(programName)\ \"\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ nameStyle\ \[expr\ \{\$errCount\ >\ 0\ ?\ \"style='color:\ #c00'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$errCount\ >\ 0\}\ \{\ append\ outputSuffix\ \"\ (<span\ style='font-size:\ 0.75em\;\ color:\ #c00'>\$\{errCount\}\ errors</span>)\"\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ summaryStyle\ \[expr\ \{\$outputHtml\ eq\ \"\"\ ?\ \"style='list-style:\ none'\"\ :\ \"\"\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ returnList\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ id=\"program-\[string\ map\ \{\{\ \}\ -\}\ \$item(programName)\]\"><details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary\ \$summaryStyle><span\ \$nameStyle>\$displayName</span>\ \$outputSuffix</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$outputHtml\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details></li>\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</ul>\"\n\ \ \ \ \ \ \ \ lappend\ returnList\ \"</details>\"\n\ \ \ \ \ \ \ \ join\ \$returnList\n\ \ \ \ \}\n\n\ \ \ \ fn\ emitHtmlForPrograms\ \{programs\}\ \{\n\ \ \ \ \ \ \ \ set\ vp\ \[list\]\;\ #\ builtin\ programs\n\ \ \ \ \ \ \ \ set\ cp\ \[list\]\;\ #\ local\ programs\n\ \ \ \ \ \ \ \ set\ wp\ \[list\]\;\ #\ web\ programs\n\ \ \ \ \ \ \ \ set\ rp\ \[list\]\;\ #\ real\ programs\n\n\ \ \ \ \ \ \ \ foreach\ match\ \$programs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ programName\ \[dict\ get\ \$match\ programName\]\n\ \ \ \ \ \ \ \ \ \ \ \ switch\ -glob\ \$programName\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"builtin-programs/*\"\ \{\ lappend\ vp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/home/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"/Users/*\"\ \{\ lappend\ cp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"web-program-*\"\ \{\ lappend\ wp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ default\ \{\ lappend\ rp\ \$match\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ vp\ \{programName\ \"sysmon.c\"\}\n\n\ \ \ \ \ \ \ \ return\ \[join\ \[list\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$vp\ \"builtin-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$cp\ \"local-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$rp\ \"real-programs\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \[emitHtmlForProgramList\ \$wp\ \"web-programs\"\]\ \]\]\n\ \ \ \ \}\n\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ \ \ <title>Folk:\ Running\ programs</title>\n\ \ \ \ \ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ body\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ math\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ summary\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ font-family:\ monospace\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ details\ ul\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ margin-block:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list-style-type:\ none\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script\ src=\"/vendor/idiomorph.js\"></script>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS()\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \[QueryOne!\ the\ web\ navigation\ HTML\ is\ /./\]\n\ \ \ \ \ \ \ \ \[HtmlWhen\ the\ collected\ results\ for\ \[list\ /programName/\ has\ program\ code\ /programCode/\]\ are\ /programs/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ emitHtmlForPrograms\ \$programs\n\n\ \ \ \ \ \ \ \ \}\ -beforeAttributeUpdated\ \{(attributeName,\ node,\ mutationType)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ (attributeName\ ===\ \"open\")\ \{\ return\ false\;\ \}\n\ \ \ \ \ \ \ \ \}\}\]\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/index.folk} {} {}}}
builtin-programs/web/camera.folk wishes the web server handles route /camera with handler {applyBlock (
[ m655:0 () ]
)builtin-programs/web/camera.folk wishes the web server handles route /camera with handler {applyBlock {
if {[dict exists $QUERY camera]} {
set camera [dict get $QUERY camera]
} else {
set cameraResults [Query! camera /camera/ has width /w/ height /h/]
if {[llength $cameraResults] == 1} {
set camera [dict get [lindex $cameraResults 0] camera]
} else {
return [html [subst {
<html>
<body>
<p>Choose a camera:</p>
<ul>
[join [lmap result $cameraResults { subst {
<li><a href="/camera?camera=[string map [list / %2F " " %20] $result(camera)]">$result(camera)</a></li>
} }] \n]
</ul>
</body>
</html>
}]]
}
}
# in case it's a virtual camera, we want to get the base path.
set baseCameraToControl [lindex $camera 0]
set exposuresAtPageLoad [Query! /someone/ wishes camera $baseCameraToControl uses exposure time /exposureTime/ us]
if {[llength $exposuresAtPageLoad] == 1} {
set exposureAtPageLoad [dict get [lindex $exposuresAtPageLoad 0] exposureTime]
} else {
set exposureAtPageLoad 1500
}
html [subst {
<html>
<body style="margin: 0 0">
<canvas id="cameraCanvas" style="max-width: 100%"></canvas>
<div style="padding: 8px">
<span id="statusSpan">Status</span>
<label><input type="checkbox" id="cameraAutoexposure">Auto-exposure</label>
<div style="display: inline-block" id="manualExposure">
Manual exposure:
<input style="max-width: 100px" type="range" min="10" max="48" value="15" class="slider" id="cameraExposureSlider">
<input type="number" min="1000" max="320000" step="100" value="1500" id="cameraExposureNumber">μs
</div>
</div>
<script src="/lib/folk.js"></script>
<script>
const canvas = cameraCanvas;
const ctx = canvas.getContext('2d');
function advanceCamera() {
const img = new Image();
img.onload = () => {
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
setTimeout(advanceCamera, 0);
};
img.onerror = () => setTimeout(advanceCamera, 500);
img.src = '/camera-frame?camera=[string map [list / %2F " " %20] $camera]&uniq=' + Math.random();
}
advanceCamera();
const ws = new FolkWS(statusSpan);
function sendExposure(valueInMicroseconds) {
ws.hold('exposure $baseCameraToControl', tcl`
Wish camera $baseCameraToControl uses exposure time \${valueInMicroseconds} us
`, 'builtin-programs/web/setup.folk', true);
}
function updateExposure(valueInMicroseconds, doSend = true) {
const auto = valueInMicroseconds == 0;
cameraAutoexposure.checked = auto;
cameraExposureSlider.disabled = auto;
cameraExposureNumber.disabled = auto;
manualExposure.style.opacity = auto ? 0.5 : 1;
if (!auto) {
cameraExposureSlider.value = valueInMicroseconds / 100;
cameraExposureNumber.value = valueInMicroseconds;
}
if (doSend) { sendExposure(valueInMicroseconds); }
}
cameraExposureSlider.addEventListener('input', (e) => updateExposure(Math.round(e.target.value * 100)));
cameraExposureNumber.addEventListener('input', (e) => {
let value = parseInt(e.target.value);
if (value == 0) value = 100; // just so people don't get stuck in auto.
updateExposure(value);
});
cameraAutoexposure.addEventListener('change', (e) => updateExposure(e.target.checked ? 0 : cameraExposureNumber.value));
updateExposure($exposureAtPageLoad, false)
</script>
</body>
</html>
}]
} {{this builtin-programs/web/camera.folk} {} {}}}
builtin-programs/calibrate/load-calibration.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb- (
[ m1678:0 (s2611:0) ]
[ m3382:1022 (s32233:1209) ]
[ m47756:1061 (s64527:1261) ]
[ m31647:1059 () ]
[ m31689:1059 () ]
[ m31811:1064 () ]
[ m31835:1066 () ]
[ m31856:1067 () ]
[ m31890:1067 () ]
[ m31920:1067 () ]
)builtin-programs/calibrate/load-calibration.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has intrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602}
builtin-programs/calibrate/load-calibration.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb- (
[ m1385:0 (s2241:0 s2242:0) ]
)builtin-programs/calibrate/load-calibration.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor has extrinsics {R {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} t {0.00950987780512 0.0157209796983 0.70557852591}}
builtin-programs/calibrate/load-calibration.folk claims display monitor has intrinsics {width 4096 he (
[ m23563:0 (s31205:0) ]
[ m23615:0 (s31283:0) ]
[ m23650:0 (s31334:0) ]
[ m23657:0 (s31346:0) ]
[ m60959:856 () ]
[ m60149:888 () ]
[ m6534:945 (s53056:1174) ]
)builtin-programs/calibrate/load-calibration.folk claims display monitor has intrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249}
builtin-programs/calibrate/model.folk claims the calibration model library is <library:/tmp/modelLib_ (
[ m724:0 (s1116:0) ]
[ m1047:0 (s1832:0) ]
[ m23570:0 (s31214:0) ]
[ m23574:0 (s31221:0) ]
)builtin-programs/calibrate/model.folk claims the calibration model library is <library:/tmp/modelLib_OwSqeI.tcl>
builtin-programs/calibrate/calibrate.folk claims the calibration poses max is 10 (
[ m4487:0 (s6286:0) ]
)builtin-programs/calibrate/calibrate.folk claims the calibration poses max is 10
builtin-programs/calibrate/calibrate.folk claims the calibration poses from camera /dev/v4l/by-path/p (
[ m1053:0 (s1850:0 s1854:0) ]
[ m4489:0 (s6294:0) ]
)builtin-programs/calibrate/calibrate.folk claims the calibration poses from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor are {{model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 28 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-75314.698413 4478.401730 19997.029253 }{-971.492484 -71792.210770 22876.355728 }{-1.407849 2.419020 18.216270 }} rmse 0.725728225238 tags {48601 {id 48601 c {1385.029589 373.397601} p {{1367.431885 391.921936} {1405.210205 389.762604} {1402.768921 354.724182} {1364.972778 357.132996}} size 37 angle 0.057096} 48603 {id 48603 c {1538.393435 364.163451} p {{1520.251709 382.996368} {1560.268555 380.483032} {1556.391846 345.479309} {1516.824951 348.072632}} size 40 angle 0.062725} 48604 {id 48604 c {1314.707595 447.429039} p {{1296.983887 465.832520} {1334.821533 464.710083} {1332.746704 428.698059} {1294.883911 430.397369}} size 37 angle 0.029656} 48606 {id 48606 c {1466.610059 439.916687} p {{1448.426758 459.265656} {1487.840576 457.079193} {1484.453857 420.928986} {1445.619263 422.947968}} size 39 angle 0.055418} 48609 {id 48609 c {1394.987112 514.999554} p {{1377.006226 533.712585} {1415.902588 532.740601} {1413.313599 495.926849} {1374.507446 497.628174}} size 38 angle 0.024984} 48611 {id 48611 c {1551.315859 508.245212} p {{1533.442505 527.498169} {1572.451660 526.567932} {1569.045044 489.147552} {1530.549683 490.242920}} size 39 angle 0.023842} 48612 {id 48612 c {1323.958123 589.924482} p {{1306.240601 608.614990} {1344.435791 607.666931} {1341.827026 571.074280} {1303.762695 572.426575}} size 38 angle 0.024816} 48614 {id 48614 c {1479.024930 584.982536} p {{1460.857666 603.967041} {1500.821045 602.853821} {1497.578369 565.594482} {1457.400269 567.251831}} size 39 angle 0.027849} 48617 {id 48617 c {1406.285006 661.290040} p {{1388.146118 680.364746} {1427.638062 679.629700} {1424.388550 642.252502} {1385.154663 643.141663}} size 39 angle 0.018610} 48619 {id 48619 c {1565.543612 657.303678} p {{1547.084473 676.826904} {1587.975098 675.831177} {1583.959351 637.826355} {1543.498535 639.095337}} size 40 angle 0.024346} 48600 {id 48600 c {1311.069046 378.239945} p {{1293.403809 397.174408} {1331.194946 394.612976} {1328.710938 359.330505} {1291.372437 362.216156}} size 37 angle 0.067675} 48602 {id 48602 c {1460.901364 369.680924} p {{1443.130371 388.178741} {1482.119629 386.910889} {1479.017700 350.823639} {1440.809570 353.365692}} size 39 angle 0.032507} 48605 {id 48605 c {1390.772515 444.293298} p {{1372.398560 463.838928} {1411.644775 461.251099} {1408.589966 425.339661} {1369.880737 427.319641}} size 39 angle 0.065843} 48607 {id 48607 c {1544.826101 436.656867} p {{1526.837891 455.811432} {1566.585449 454.317230} {1563.773438 416.480988} {1523.533813 419.375580}} size 39 angle 0.037575} 48608 {id 48608 c {1320.136780 518.359033} p {{1302.109009 537.349243} {1340.637085 535.987244} {1338.151733 499.382324} {1299.486084 500.601501}} size 38 angle 0.035336} 48610 {id 48610 c {1472.920554 512.574182} p {{1454.544067 531.717834} {1494.853027 530.374573} {1491.634033 493.079468} {1451.511475 495.198578}} size 40 angle 0.033312} 48613 {id 48613 c {1401.442760 587.735040} p {{1383.686401 606.712585} {1422.481323 605.905945} {1419.349243 568.597046} {1380.474243 569.624634}} size 38 angle 0.020789} 48615 {id 48615 c {1558.880689 582.530694} p {{1540.743286 601.986816} {1580.547241 600.764343} {1576.885620 563.216675} {1537.027832 564.140259}} size 39 angle 0.030703} 48616 {id 48616 c {1329.655113 663.051861} p {{1311.354126 682.407532} {1350.495972 681.459778} {1347.780396 643.882019} {1309.224487 645.006287}} size 39 angle 0.024209} 48618 {id 48618 c {1486.141093 659.716024} p {{1467.177856 679.632935} {1507.811157 677.993408} {1504.760864 640.159851} {1464.393188 641.372986}} size 40 angle 0.040327}} imageName pose-1781543257841-0.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 43 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1056840.114219 42808.811083 264863.141447 }{32312.866960 -1007364.955709 402770.605979 }{-11.182218 42.695320 245.704300 }} rmse 1.89131853376 tags {48601 {id 48601 c {1395.952641 212.861420} p {{1377.588257 233.639587} {1417.538696 229.658676} {1414.197876 192.218063} {1374.617188 196.259171}} size 40 angle 0.099318} 48603 {id 48603 c {1553.635336 197.600660} p {{1535.305908 218.149307} {1575.980347 214.534927} {1571.934326 177.086136} {1531.557007 180.868500}} size 40 angle 0.088628} 48604 {id 48604 c {1324.137968 293.707576} p {{1306.116943 313.840912} {1345.083008 310.326050} {1341.587646 274.212555} {1303.338867 277.204895}} size 39 angle 0.089960} 48606 {id 48606 c {1480.843873 279.367657} p {{1462.405518 299.948456} {1502.627686 296.394623} {1499.185791 258.894501} {1459.289917 262.520355}} size 40 angle 0.088126} 48609 {id 48609 c {1408.072088 360.901788} p {{1390.102661 380.931671} {1429.527344 377.933807} {1426.243774 340.646454} {1386.851929 344.056396}} size 39 angle 0.075894} 48611 {id 48611 c {1567.259040 347.361196} p {{1549.179443 367.838379} {1588.584595 365.235809} {1584.650513 327.663391} {1546.489990 329.953033}} size 39 angle 0.065951} 48612 {id 48612 c {1336.656619 441.631250} p {{1318.508179 462.043243} {1358.458130 459.201569} {1354.721069 421.313721} {1315.223755 424.358032}} size 40 angle 0.071011} 48614 {id 48614 c {1494.646192 429.683558} p {{1476.802612 449.946777} {1516.712524 447.297180} {1512.817993 409.047607} {1472.774170 412.225037}} size 39 angle 0.066292} 48617 {id 48617 c {1423.249643 510.798629} p {{1404.714844 531.413879} {1445.430786 528.574585} {1441.903687 490.050751} {1400.936401 492.916809}} size 40 angle 0.069622} 48619 {id 48619 c {1583.746862 499.650259} p {{1566.048706 520.226074} {1606.481323 517.599731} {1601.709229 478.767273} {1560.927002 481.633362}} size 40 angle 0.064865} 48600 {id 48600 c {1318.372902 222.551387} p {{1299.982056 243.184250} {1339.737549 239.225800} {1336.857300 201.813568} {1296.936279 205.820801}} size 39 angle 0.099243} 48602 {id 48602 c {1474.613028 207.413025} p {{1456.190552 227.932159} {1496.754761 224.579254} {1493.370117 186.521194} {1452.811646 190.510666}} size 40 angle 0.082469} 48605 {id 48605 c {1402.289206 288.773703} p {{1381.081299 272.196045} {1383.976074 309.481049} {1423.905273 305.670410} {1420.299072 268.409271}} size 37 angle -1.493313} 48607 {id 48607 c {1560.824988 274.287257} p {{1542.879883 294.537292} {1582.193848 292.009033} {1578.751343 254.058380} {1539.623535 256.704315}} size 39 angle 0.064221} 48608 {id 48608 c {1330.693159 369.828011} p {{1312.406006 390.445038} {1352.469727 386.978882} {1349.092041 349.085022} {1309.401855 353.059326}} size 40 angle 0.086301} 48610 {id 48610 c {1488.474183 356.547666} p {{1469.599854 377.690796} {1510.819702 373.957123} {1506.693237 336.138580} {1466.973022 339.796051}} size 41 angle 0.090333} 48613 {id 48613 c {1416.229342 437.995789} p {{1394.115112 420.463196} {1397.874268 459.000122} {1438.656128 455.776184} {1434.263916 417.358215}} size 38 angle -1.473557} 48615 {id 48615 c {1575.955360 426.006059} p {{1557.106689 447.186432} {1598.870117 444.503754} {1594.429932 405.246063} {1553.894043 408.197296}} size 41 angle 0.064147} 48616 {id 48616 c {1344.023531 519.212660} p {{1325.910889 539.723450} {1366.120361 537.195007} {1362.370117 498.436951} {1322.228394 501.475830}} size 40 angle 0.062799} 48618 {id 48618 c {1504.497483 507.714315} p {{1485.648682 528.901550} {1527.599365 526.065979} {1523.404175 486.462006} {1481.829468 489.707306}} size 42 angle 0.067490}} imageName pose-1781543257841-1.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 64 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-209693.666866 32261.725933 45616.235897 }{9716.750647 -182727.705443 69957.706876 }{1.369661 20.418735 41.956332 }} rmse 1.12427806234 tags {48601 {id 48601 c {1509.711328 54.434227} p {{1480.648926 85.984230} {1536.133667 82.819717} {1538.859497 22.791117} {1483.493286 26.268213}} size 55 angle 0.056972} 48604 {id 48604 c {1394.354083 178.405525} p {{1365.312988 209.825806} {1421.084839 206.090240} {1423.003174 147.409363} {1367.770142 150.872864}} size 55 angle 0.066880} 48606 {id 48606 c {1610.914251 165.377982} p {{1581.291260 195.974930} {1636.133911 193.269714} {1640.511963 134.807144} {1585.921265 137.736938}} size 54 angle 0.049287} 48609 {id 48609 c {1495.829713 283.255061} p {{1467.725464 311.925690} {1520.545898 308.731995} {1524.365112 254.144592} {1470.828369 257.484192}} size 52 angle 0.060390} 48611 {id 48611 c {1706.065596 270.965025} p {{1678.112183 299.655853} {1728.069824 296.962830} {1733.845215 242.452576} {1684.113159 245.028412}} size 50 angle 0.053854} 48612 {id 48612 c {1385.763556 396.781625} p {{1358.841064 424.564758} {1411.064087 421.179443} {1412.717529 368.966003} {1360.271606 372.199219}} size 52 angle 0.064734} 48614 {id 48614 c {1592.767882 384.014632} p {{1565.013916 411.650513} {1615.941650 408.255951} {1620.917480 355.984802} {1568.793213 358.935516}} size 51 angle 0.066556} 48617 {id 48617 c {1484.082987 492.101955} p {{1456.933105 518.884766} {1508.521606 515.551514} {1511.408203 465.146179} {1459.290771 468.313110}} size 51 angle 0.064523} 48619 {id 48619 c {1684.106845 479.581249} p {{1656.806152 506.011230} {1707.054565 503.155701} {1711.697510 452.870544} {1661.051270 455.895996}} size 50 angle 0.056767} 48600 {id 48600 c {1399.789822 59.409994} p {{1369.518433 92.648804} {1426.722534 87.997520} {1428.329834 28.072285} {1372.388428 30.324989}} size 57 angle 0.081132} 48602 {id 48602 c {1620.425256 46.876868} p {{1590.636230 78.148476} {1645.181152 75.500832} {1650.330200 15.483572} {1595.297729 17.823208}} size 54 angle 0.048503} 48605 {id 48605 c {1502.972095 171.263498} p {{1473.294922 202.666061} {1529.038208 199.092056} {1532.439453 140.082947} {1476.357422 142.849289}} size 55 angle 0.064028} 48607 {id 48607 c {1716.798563 158.749720} p {{1687.903442 188.728394} {1740.135620 186.814194} {1747.215942 127.191704} {1692.823486 129.917984}} size 52 angle 0.036632} 48608 {id 48608 c {1389.683476 289.345012} p {{1361.929688 318.369263} {1415.511719 314.445282} {1418.558594 259.148102} {1363.436646 263.837952}} size 53 angle 0.073103} 48610 {id 48610 c {1601.362012 276.392144} p {{1572.501587 305.586060} {1625.155640 301.927612} {1630.324951 247.094528} {1577.106812 250.361313}} size 52 angle 0.069369} 48613 {id 48613 c {1489.824889 389.421889} p {{1462.307617 417.067352} {1514.499268 414.530518} {1517.472290 361.645691} {1465.068970 364.230286}} size 52 angle 0.048568} 48615 {id 48615 c {1694.785648 376.578606} p {{1666.799194 404.401581} {1716.849487 401.537170} {1721.927124 349.595673} {1672.444946 351.306854}} size 50 angle 0.057168} 48616 {id 48616 c {1381.972820 497.565982} p {{1355.683105 523.804565} {1407.246094 521.063721} {1409.440552 470.151672} {1356.126343 473.535309}} size 51 angle 0.053105} 48618 {id 48618 c {1585.154532 484.068682} p {{1557.027588 511.571320} {1609.122559 507.884888} {1612.781616 457.054810} {1561.358398 460.423279}} size 52 angle 0.070646}} imageName pose-1781543257841-2.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 84 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{98796.033601 -6946652.610637 2196614.745495 }{6739896.207720 460527.950943 1149462.297906 }{-190.312892 -80.550321 1480.650980 }} rmse 1.96923416025 tags {48601 {id 48601 c {1194.241663 327.654893} p {{1222.111084 348.784912} {1216.369019 300.245178} {1166.462280 306.593140} {1172.062500 355.128784}} size 48 angle 1.688545} 48603 {id 48603 c {1171.725758 137.153038} p {{1199.847046 158.204208} {1193.673950 110.035004} {1143.998901 116.397133} {1149.260986 164.909332}} size 48 angle 1.698256} 48604 {id 48604 c {1308.752097 412.254488} p {{1338.622192 434.530487} {1331.861450 384.154022} {1279.358032 390.333496} {1285.766602 440.204346}} size 50 angle 1.704204} 48606 {id 48606 c {1282.569227 218.915396} p {{1311.468262 240.157288} {1305.318115 190.902405} {1253.950073 197.879227} {1260.240479 246.411026}} size 49 angle 1.695017} 48609 {id 48609 c {1397.995160 301.536987} p {{1428.077271 322.549194} {1420.253662 274.268646} {1368.598511 281.003571} {1375.678467 328.876617}} size 48 angle 1.731445} 48611 {id 48611 c {1370.183598 111.469475} p {{1399.739502 131.376297} {1391.639771 85.337204} {1341.105835 91.884697} {1348.329224 138.086731}} size 46 angle 1.744946} 48612 {id 48612 c {1519.304013 386.697516} p {{1550.766846 409.180939} {1541.709717 358.774933} {1489.093506 365.109009} {1495.861572 415.912109}} size 51 angle 1.748583} 48614 {id 48614 c {1486.619487 192.485437} p {{1517.266602 213.760712} {1508.706177 165.099457} {1456.419800 171.520767} {1463.944824 220.600464}} size 49 angle 1.744933} 48617 {id 48617 c {1607.958935 275.600540} p {{1639.266846 297.007874} {1629.765137 248.022018} {1577.122803 254.515793} {1586.114258 303.227722}} size 49 angle 1.762386} 48619 {id 48619 c {1571.899693 85.866461} p {{1602.301147 106.652153} {1592.920166 59.605083} {1542.627441 65.852814} {1550.401001 112.725288}} size 47 angle 1.767611} 48600 {id 48600 c {1206.794202 426.590988} p {{1236.492432 449.318146} {1229.803345 398.072601} {1177.802734 404.404694} {1183.689575 455.227722}} size 51 angle 1.700593} 48602 {id 48602 c {1184.021152 232.821101} p {{1212.459473 253.815598} {1207.137085 204.863739} {1155.541260 211.795914} {1161.424805 260.150055}} size 49 angle 1.679098} 48605 {id 48605 c {1296.399419 316.668400} p {{1325.864990 337.833160} {1318.705078 289.045715} {1267.292847 295.761505} {1274.157593 344.212036}} size 49 angle 1.716513} 48607 {id 48607 c {1272.569361 125.751695} p {{1301.373169 146.699203} {1294.984741 99.184029} {1244.206299 105.124718} {1249.886353 152.636566}} size 47 angle 1.704445} 48608 {id 48608 c {1414.667729 402.124332} p {{1445.368042 424.986145} {1437.862793 373.319275} {1384.357422 379.552948} {1391.050537 431.453613}} size 52 angle 1.715050} 48610 {id 48610 c {1385.344625 207.908486} p {{1415.355225 229.484650} {1408.298096 180.034698} {1355.682983 186.583206} {1362.748413 235.348434}} size 49 angle 1.712552} 48613 {id 48613 c {1504.010825 290.592138} p {{1535.192505 311.400970} {1525.939331 263.201904} {1472.870605 269.810974} {1482.175293 317.866241}} size 49 angle 1.760467} 48615 {id 48615 c {1472.653357 100.909178} p {{1503.442139 121.380783} {1494.246338 74.729080} {1443.124634 81.275391} {1450.703613 127.521828}} size 47 angle 1.765417} 48616 {id 48616 c {1627.703024 377.014268} p {{1659.892212 399.384186} {1649.839233 348.795959} {1595.999512 354.981873} {1604.796143 406.214996}} size 51 angle 1.766962} 48618 {id 48618 c {1590.935498 182.266953} p {{1622.018433 204.144791} {1613.073486 154.467285} {1560.334961 160.728653} {1568.566406 210.356827}} size 50 angle 1.748948}} imageName pose-1781543257841-3.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 99 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-164.252607 -820.689643 321.050974 }{657.240586 2.194841 74.671280 }{-0.091003 -0.007578 0.199975 }} rmse 1.60197092768 tags {48601 {id 48601 c {1141.550955 582.403096} p {{1161.815552 600.761658} {1163.238403 562.024231} {1120.927490 563.719421} {1120.484253 602.198669}} size 38 angle 1.534082} 48603 {id 48603 c {1145.788283 418.406845} p {{1167.404541 439.410339} {1168.944092 395.168213} {1123.939575 397.177490} {1122.794189 441.483185}} size 44 angle 1.536012} 48604 {id 48604 c {1221.678530 654.892956} p {{1241.052490 672.530945} {1243.321289 635.811279} {1201.962158 636.943237} {1200.216064 673.815674}} size 36 angle 1.509088} 48606 {id 48606 c {1229.823309 499.788624} p {{1250.237061 519.468994} {1253.126953 477.784363} {1208.700195 479.424377} {1206.813232 521.515686}} size 41 angle 1.501580} 48609 {id 48609 c {1309.572061 576.229695} p {{1329.272949 595.172302} {1332.628296 555.744568} {1289.946289 557.359314} {1286.864502 596.405029}} size 39 angle 1.485900} 48611 {id 48611 c {1324.503629 410.281911} p {{1345.424316 431.919800} {1348.665894 386.653442} {1303.432983 388.488922} {1300.430908 433.822815}} size 45 angle 1.499307} 48612 {id 48612 c {1386.199225 649.691146} p {{1405.200684 668.071045} {1409.600952 630.438660} {1367.856934 631.948853} {1363.365601 668.476257}} size 37 angle 1.454397} 48614 {id 48614 c {1404.546747 492.311979} p {{1424.596436 512.734863} {1429.509399 470.110352} {1384.809814 472.207672} {1379.893799 514.238159}} size 42 angle 1.456041} 48617 {id 48617 c {1481.319865 570.522647} p {{1500.176636 589.614075} {1506.079590 549.730896} {1462.400513 551.367859} {1457.022339 590.926270}} size 40 angle 1.423857} 48619 {id 48619 c {1505.624037 402.192051} p {{1525.058838 423.735840} {1531.934570 378.371429} {1485.980469 380.416840} {1479.559814 425.789673}} size 45 angle 1.420375} 48600 {id 48600 c {1138.113454 658.341403} p {{1157.728149 676.412109} {1159.237061 639.123474} {1118.033081 639.841675} {1117.274170 677.300659}} size 37 angle 1.530353} 48602 {id 48602 c {1141.823652 502.541629} p {{1163.265625 522.951355} {1164.351807 480.563751} {1119.985718 481.755005} {1119.635254 524.188049}} size 42 angle 1.545177} 48605 {id 48605 c {1223.377045 580.184804} p {{1201.270752 599.937561} {1243.418579 599.076233} {1245.842407 560.111206} {1203.125610 561.095520}} size 42 angle 0.020433} 48607 {id 48607 c {1232.657392 413.568093} p {{1254.376343 435.440247} {1256.473877 390.930359} {1211.246704 392.006378} {1208.927002 436.123993}} size 44 angle 1.523706} 48608 {id 48608 c {1301.878842 653.889951} p {{1320.725586 671.876770} {1324.375000 634.329895} {1282.553223 635.446106} {1278.991821 673.789856}} size 37 angle 1.473904} 48610 {id 48610 c {1314.763363 497.048578} p {{1335.116821 517.577820} {1339.197754 475.334717} {1294.032349 476.138519} {1290.772095 518.368652}} size 42 angle 1.474489} 48613 {id 48613 c {1393.748209 574.806004} p {{1369.902954 595.453003} {1413.156860 593.946838} {1417.280640 554.429871} {1373.905273 555.236877}} size 43 angle 0.034807} 48615 {id 48615 c {1412.617496 407.403562} p {{1433.579224 429.078918} {1438.576172 383.783478} {1391.769043 385.845337} {1387.735352 430.044098}} size 45 angle 1.460922} 48616 {id 48616 c {1468.586555 649.108080} p {{1487.397583 667.221069} {1492.819580 629.765076} {1450.277710 631.478638} {1444.668457 668.199707}} size 37 angle 1.427038} 48618 {id 48618 c {1491.469528 490.510814} p {{1510.942993 511.321289} {1517.885132 468.175201} {1472.139771 469.853912} {1465.745728 512.261475}} size 43 angle 1.411265}} imageName pose-1781543257841-4.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 113 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-652.045996 -21.596042 316.832491 }{38.585632 -605.150208 263.674429 }{-0.025238 0.018629 0.147826 }} rmse 2.01227215325 tags {48601 {id 48601 c {977.930902 159.133678} p {{961.526062 180.890030} {998.662842 173.187088} {994.492188 137.169846} {957.513733 145.293640}} size 37 angle 0.204521} 48603 {id 48603 c {1128.442555 127.285638} p {{1111.380981 149.230835} {1150.937012 141.910492} {1145.978394 104.730423} {1106.935059 113.302460}} size 40 angle 0.182992} 48604 {id 48604 c {913.613811 244.410072} p {{897.504028 265.617676} {933.629150 258.775940} {929.834473 223.056503} {893.546875 230.007172}} size 36 angle 0.187173} 48606 {id 48606 c {1061.222644 215.459666} p {{1044.215210 237.679565} {1082.993774 230.328522} {1078.232056 193.237183} {1039.661499 200.734222}} size 39 angle 0.187342} 48609 {id 48609 c {994.600018 302.540949} p {{978.372559 323.581116} {1015.690918 317.462067} {1011.314331 280.869537} {973.992737 287.961975}} size 37 angle 0.162523} 48611 {id 48611 c {1148.040286 274.979104} p {{1130.848511 296.855865} {1170.356934 290.619507} {1165.280518 253.040680} {1125.903931 259.465057}} size 39 angle 0.156557} 48612 {id 48612 c {929.044403 388.400978} p {{912.621643 409.819275} {949.752258 403.972961} {945.610474 366.795776} {909.082642 373.390045}} size 37 angle 0.156171} 48614 {id 48614 c {1079.629903 363.319986} p {{1062.534424 385.340088} {1101.736694 378.890747} {1096.727173 341.297577} {1058.058228 348.126129}} size 39 angle 0.163054} 48617 {id 48617 c {1011.995130 450.385611} p {{994.765564 472.561249} {1033.851685 466.870331} {1029.125000 428.338287} {990.725464 434.343536}} size 39 angle 0.144583} 48619 {id 48619 c {1168.522487 426.853393} p {{1150.667725 449.554413} {1191.837036 443.555511} {1186.205078 404.371277} {1145.656982 410.472961}} size 41 angle 0.144695} 48600 {id 48600 c {906.411835 177.815006} p {{889.984741 199.787430} {926.487671 191.674118} {922.554993 156.222366} {886.374207 163.982269}} size 37 angle 0.218709} 48602 {id 48602 c {1051.843604 146.397340} p {{1034.971924 168.697723} {1073.739624 160.711548} {1068.651978 124.180634} {1030.366455 132.356964}} size 39 angle 0.203159} 48605 {id 48605 c {986.661165 233.698148} p {{1007.705933 248.093491} {1003.319397 211.708145} {965.541809 219.251785} {970.112244 255.543854}} size 36 angle 1.690775} 48607 {id 48607 c {1137.807079 202.742391} p {{1120.361816 225.086212} {1160.317017 218.317123} {1155.167358 180.507416} {1115.311768 187.177780}} size 40 angle 0.167823} 48608 {id 48608 c {922.560991 318.546825} p {{906.624146 340.189362} {942.870178 333.020996} {938.391785 297.048309} {902.168701 304.013428}} size 36 angle 0.195250} 48610 {id 48610 c {1070.498044 291.328487} p {{1053.658569 313.241547} {1092.294434 306.299133} {1087.534180 269.159515} {1048.903076 276.496185}} size 39 angle 0.177791} 48613 {id 48613 c {1004.548424 378.170736} p {{1026.171143 393.921082} {1021.375305 356.460602} {983.372803 362.746063} {987.668945 399.948730}} size 37 angle 1.698128} 48615 {id 48615 c {1158.497567 351.624066} p {{1141.118408 373.867371} {1181.446045 367.684326} {1175.558594 329.787933} {1136.038452 335.906281}} size 40 angle 0.152136} 48616 {id 48616 c {939.220193 463.734392} p {{922.379578 485.613617} {960.984741 480.247101} {955.976013 441.965332} {918.181152 447.772125}} size 38 angle 0.138125} 48618 {id 48618 c {1090.522811 440.062316} p {{1073.001709 463.023590} {1113.502075 456.692810} {1107.943359 417.232819} {1068.055298 423.802185}} size 40 angle 0.155059}} imageName pose-1781543257841-5.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 127 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-61350.964391 13718.747912 28186.840504 }{4013.252826 -47158.607425 24253.415873 }{0.442939 7.990373 13.206176 }} rmse 2.0423236365 tags {48601 {id 48601 c {995.655720 63.369710} p {{973.477661 90.745377} {1019.583435 88.357903} {1018.224365 35.511921} {971.392822 38.031479}} size 46 angle 0.051736} 48603 {id 48603 c {1180.455537 53.052164} p {{1156.181641 80.391281} {1202.452759 77.794220} {1204.506226 25.964441} {1158.137085 27.948795}} size 46 angle 0.056068} 48604 {id 48604 c {910.089626 169.639338} p {{889.396729 195.435806} {934.235474 192.824677} {931.088196 143.461807} {885.473083 146.002029}} size 44 angle 0.058168} 48606 {id 48606 c {1087.511228 159.278386} p {{1065.120605 184.974594} {1109.740112 182.464233} {1110.227051 133.208969} {1065.099487 135.901810}} size 44 angle 0.056202} 48609 {id 48609 c {1001.921881 257.661450} p {{981.454956 281.020996} {1023.606201 278.443939} {1022.982117 233.624741} {979.547729 236.217819}} size 42 angle 0.061062} 48611 {id 48611 c {1172.079885 247.141943} p {{1150.322266 270.640564} {1191.790283 267.688171} {1194.587402 222.833420} {1151.829712 226.033051}} size 41 angle 0.071077} 48612 {id 48612 c {922.703804 348.671427} p {{903.591309 370.806976} {944.802917 368.033569} {941.781982 326.575623} {900.360535 329.095367}} size 41 angle 0.067195} 48614 {id 48614 c {1086.742713 338.234140} p {{1066.020996 360.519623} {1107.078979 357.741791} {1107.172485 316.262634} {1066.420776 318.740234}} size 41 angle 0.067553} 48617 {id 48617 c {1007.363271 423.517549} p {{987.993103 444.138885} {1027.957153 441.846527} {1026.905151 402.713409} {987.214966 405.585144}} size 40 angle 0.057298} 48619 {id 48619 c {1165.054318 412.989596} p {{1144.602783 433.873840} {1183.831665 430.969727} {1185.664429 391.943420} {1146.122681 394.861725}} size 39 angle 0.073895} 48600 {id 48600 c {901.093923 70.459400} p {{879.565063 98.831100} {926.215210 95.174049} {922.728394 41.948521} {875.173706 44.958752}} size 46 angle 0.078233} 48602 {id 48602 c {1085.779535 59.660986} p {{1062.445923 87.665062} {1108.789673 85.055267} {1109.044922 31.738792} {1062.930176 34.444141}} size 46 angle 0.056254} 48605 {id 48605 c {997.285938 166.825402} p {{973.270996 143.105530} {975.749329 192.658005} {1021.540161 190.781616} {1018.919434 140.876587}} size 49 angle -1.520824} 48607 {id 48607 c {1173.617485 154.937350} p {{1150.805542 180.724335} {1195.427490 177.985092} {1197.802246 127.598511} {1151.804687 131.886658}} size 44 angle 0.061311} 48608 {id 48608 c {915.100492 265.275558} p {{895.314270 289.225830} {938.357666 286.459778} {935.249207 240.886505} {891.717712 243.976929}} size 43 angle 0.064174} 48610 {id 48610 c {1085.493242 255.170662} p {{1064.236572 278.830505} {1106.522827 275.830505} {1107.605225 230.558807} {1063.488892 233.553192}} size 42 angle 0.070826} 48613 {id 48613 c {1003.760979 346.516282} p {{982.015869 326.394714} {984.393250 368.502594} {1025.032593 366.199707} {1023.765808 323.806732}} size 42 angle -1.514397} 48615 {id 48615 c {1167.279457 334.932959} p {{1146.137329 356.945221} {1186.635132 354.646179} {1188.529785 312.808044} {1147.281250 314.565338}} size 40 angle 0.056709} 48616 {id 48616 c {927.208690 432.071257} p {{908.725525 452.526123} {949.156921 450.607025} {946.694458 410.506836} {905.706055 413.911804}} size 40 angle 0.047430} 48618 {id 48618 c {1085.678921 420.576598} p {{1065.630981 441.996979} {1105.944946 439.000702} {1105.520752 399.376434} {1065.620117 402.340881}} size 40 angle 0.074187}} imageName pose-1781543257841-6.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 139 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1293234.230097 -236546.444378 661933.879650 }{123504.689570 -1164505.518365 389497.399567 }{-24.466768 -74.390643 296.571025 }} rmse 1.41663092406 tags {48601 {id 48601 c {949.478206 319.501544} p {{930.948975 336.128265} {970.724487 329.256683} {967.531921 303.301514} {928.905212 310.055542}} size 40 angle 0.171071} 48603 {id 48603 c {1108.382342 293.125748} p {{1091.457397 309.351135} {1132.334351 302.969696} {1125.304199 276.903320} {1085.332153 283.652435}} size 41 angle 0.154863} 48604 {id 48604 c {873.740912 387.403626} p {{853.658752 405.510284} {894.607117 398.498199} {893.467712 369.617371} {852.656311 376.192932}} size 41 angle 0.169597} 48606 {id 48606 c {1038.223024 362.779168} p {{1020.033813 380.388397} {1062.753662 374.629364} {1056.753296 344.839752} {1015.530884 351.817108}} size 43 angle 0.134001} 48609 {id 48609 c {962.427428 434.368246} p {{941.884705 454.018036} {986.398438 446.855377} {982.145691 415.507080} {938.896179 422.110199}} size 45 angle 0.159541} 48611 {id 48611 c {1138.240590 411.331288} p {{1119.195923 430.997711} {1164.848633 424.473511} {1155.939697 393.054352} {1111.961914 398.351746}} size 46 angle 0.141948} 48612 {id 48612 c {878.276910 515.929814} p {{855.905457 537.082336} {902.737427 530.844604} {900.828247 494.607208} {855.529419 502.059540}} size 47 angle 0.132415} 48614 {id 48614 c {1062.340061 487.695207} p {{1041.345215 509.091980} {1089.702148 502.621124} {1082.033081 467.625183} {1035.657471 473.139954}} size 48 angle 0.133024} 48617 {id 48617 c {977.755158 575.323222} p {{955.283936 598.861938} {1005.151978 591.779480} {999.932617 552.092224} {951.709961 559.678833}} size 50 angle 0.141080} 48619 {id 48619 c {1175.241702 547.766057} p {{1155.157227 570.688110} {1206.051147 564.145264} {1194.967285 525.253601} {1145.051514 531.716064}} size 51 angle 0.127857} 48600 {id 48600 c {869.726321 330.031056} p {{850.153198 347.147217} {890.231140 340.157562} {888.217468 313.861053} {849.431213 320.008118}} size 40 angle 0.172665} 48602 {id 48602 c {1027.292091 304.874545} p {{1009.680237 321.058594} {1050.356445 314.883850} {1045.061035 288.546143} {1005.118835 295.251953}} size 41 angle 0.150652} 48605 {id 48605 c {954.464210 373.169764} p {{932.091919 362.031342} {934.827820 391.160309} {977.714783 384.745453} {973.484131 355.744019}} size 29 angle -1.477147} 48607 {id 48607 c {1121.511416 347.373795} p {{1103.990112 365.026520} {1147.302490 359.805634} {1139.057983 329.695618} {1097.288696 335.697937}} size 43 angle 0.119962} 48608 {id 48608 c {874.893165 446.438284} p {{853.459473 466.811462} {898.051331 459.668365} {895.612122 426.744476} {852.912964 433.881165}} size 45 angle 0.158839} 48610 {id 48610 c {1049.016566 421.271853} p {{1029.286255 440.778168} {1074.801270 434.455658} {1068.158569 402.347168} {1023.870789 408.414734}} size 45 angle 0.138027} 48613 {id 48613 c {968.935134 500.034932} p {{943.878113 485.345337} {947.116699 521.777832} {995.350952 515.521118} {990.469421 478.575195}} size 36 angle -1.482137} 48615 {id 48615 c {1154.787958 474.180003} p {{1135.341919 495.410980} {1184.017578 489.054199} {1173.784912 453.439331} {1126.531982 459.801270}} size 49 angle 0.129860} 48616 {id 48616 c {880.531426 588.127394} p {{856.710999 611.316040} {906.284851 605.006714} {904.167236 565.118469} {855.683960 571.841858}} size 49 angle 0.126591} 48618 {id 48618 c {1075.733811 560.537017} p {{1054.046997 584.490234} {1104.965942 577.225769} {1096.608521 537.480774} {1047.277100 544.290955}} size 51 angle 0.141711}} imageName pose-1781543257841-7.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 158 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-3671321.265916 -136949.507711 2544618.126158 }{710108.103504 -4109714.560197 1388714.600088 }{203.442819 176.896104 872.758912 }} rmse 1.7736504896 tags {48601 {id 48601 c {642.392194 133.357953} p {{617.967773 158.737991} {672.279236 157.610672} {666.108459 108.713776} {612.277710 108.920670}} size 54 angle 0.020754} 48603 {id 48603 c {844.852518 132.784390} p {{822.703674 157.752472} {871.943237 155.121231} {865.329102 109.701424} {816.836548 109.684662}} size 49 angle 0.053387} 48604 {id 48604 c {544.373174 234.091164} p {{518.562195 260.513550} {575.344910 258.714539} {570.413330 207.434174} {512.823120 209.008011}} size 56 angle 0.031672} 48606 {id 48606 c {758.088901 229.356579} p {{735.210571 254.415009} {786.411987 252.761688} {780.482178 204.829422} {728.771057 205.129440}} size 51 angle 0.032279} 48609 {id 48609 c {665.531838 330.499630} p {{641.712585 356.745972} {695.350830 354.274567} {689.092102 304.538666} {635.630066 306.658691}} size 53 angle 0.046043} 48611 {id 48611 c {868.893259 319.759095} p {{847.957031 344.389862} {895.765808 342.600800} {889.633667 295.358704} {841.706055 296.649933}} size 47 angle 0.037404} 48612 {id 48612 c {567.420051 439.360050} p {{541.064819 468.426208} {599.423706 463.539520} {593.042664 411.101868} {535.535828 415.270813}} size 58 angle 0.083540} 48614 {id 48614 c {782.684121 422.996243} p {{759.732910 450.327362} {812.032654 445.964630} {805.213684 396.167236} {753.646423 400.271118}} size 52 angle 0.083225} 48617 {id 48617 c {690.240621 532.690635} p {{665.525635 561.614380} {720.572815 555.544250} {714.737122 504.022583} {659.297363 509.376617}} size 55 angle 0.109828} 48619 {id 48619 c {894.948644 511.727718} p {{873.199768 539.352783} {923.236877 534.105225} {916.227539 484.699615} {866.586121 489.291443}} size 50 angle 0.104491} 48600 {id 48600 c {534.750759 135.390685} p {{508.569702 161.553513} {566.256531 161.074783} {560.640137 109.519333} {502.975861 109.487190}} size 57 angle 0.008299} 48602 {id 48602 c {746.947710 134.937998} p {{723.971497 159.439575} {776.209045 159.769836} {769.576782 110.806610} {717.985352 110.359879}} size 52 angle -0.006322} 48605 {id 48605 c {655.668106 233.310392} p {{680.179504 207.696640} {624.799927 208.207703} {631.000854 259.087006} {685.842834 257.849152}} size 55 angle -3.132365} 48607 {id 48607 c {856.791753 227.330298} p {{835.554993 251.461700} {884.879150 251.208878} {878.426758 202.746368} {829.209656 203.881302}} size 49 angle 0.005126} 48608 {id 48608 c {556.857705 337.416902} p {{531.402344 365.235870} {588.602234 361.786133} {581.787415 310.172394} {524.963501 312.932770}} size 57 angle 0.060237} 48610 {id 48610 c {771.564042 327.611774} p {{749.380554 353.552917} {799.942505 350.367218} {793.670471 301.760742} {742.782227 304.532898}} size 50 angle 0.062923} 48613 {id 48613 c {680.121954 433.080485} p {{704.556458 405.732422} {649.144653 409.019745} {654.927063 461.279602} {711.183899 457.206970}} size 55 angle -3.082337} 48615 {id 48615 c {882.796758 417.159998} p {{860.786133 443.784180} {911.162842 440.625854} {903.889832 391.645691} {854.756836 393.963959}} size 50 angle 0.062612} 48616 {id 48616 c {580.346089 546.081070} p {{553.940918 575.834351} {612.320435 569.507202} {606.885620 516.176392} {547.775391 522.218018}} size 58 angle 0.107958} 48618 {id 48618 c {796.660210 523.128245} p {{773.319641 551.862793} {825.849243 545.705505} {819.719788 494.739624} {766.974731 500.166992}} size 52 angle 0.116683}} imageName pose-1781543257841-8.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 237 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-1891.405861 1041.655384 2016.225692 }{520.247195 -2581.867798 882.220288 }{0.314318 0.305814 0.589245 }} rmse 3.33980752481 tags {48601 {id 48601 c {364.371225 154.206433} p {{331.795715 179.574631} {398.034821 189.569305} {395.756592 129.765060} {330.482635 118.607208}} size 66 angle -0.149758} 48603 {id 48603 c {596.617941 193.608417} p {{569.365417 215.626068} {621.879395 224.079178} {623.512268 171.880157} {570.107422 161.631012}} size 53 angle -0.159600} 48604 {id 48604 c {233.031368 256.033977} p {{198.913910 282.412262} {268.121460 288.495392} {267.337982 229.509445} {195.164581 221.003876}} size 69 angle -0.087672} 48606 {id 48606 c {486.550832 282.978654} p {{457.602051 306.474640} {514.791077 312.368927} {514.793640 260.055664} {457.518707 252.764252}} size 57 angle -0.102704} 48609 {id 48609 c {369.163334 379.775009} p {{338.807770 404.953491} {400.322906 407.798096} {398.998322 355.028320} {336.650604 350.534973}} size 61 angle -0.046209} 48611 {id 48611 c {592.702856 393.589059} p {{566.986328 416.086365} {617.135071 418.671417} {617.891846 371.553253} {567.347168 367.558655}} size 50 angle -0.051502} 48612 {id 48612 c {245.957694 484.046393} p {{212.855713 511.161255} {280.776245 510.973358} {278.629791 457.283661} {209.693771 456.001648}} size 67 angle 0.002766} 48614 {id 48614 c {487.158600 485.320641} p {{459.366730 509.293365} {514.243896 509.179474} {514.503540 461.733429} {459.173187 460.668915}} size 54 angle 0.002075} 48617 {id 48617 c {375.237326 583.398845} p {{345.979401 609.102905} {405.023529 605.900635} {403.759338 558.341309} {344.480438 560.163757}} size 59 angle 0.054182} 48619 {id 48619 c {587.942277 574.730119} p {{563.161377 597.582275} {610.900452 594.895813} {611.961670 552.580200} {564.200806 553.876404}} size 47 angle 0.056215} 48600 {id 48600 c {226.374950 127.267377} p {{189.934280 153.998489} {264.650635 164.867844} {262.333344 100.890038} {186.153687 87.755653}} size 75 angle -0.144462} 48602 {id 48602 c {486.868933 171.379722} p {{455.991943 194.898392} {516.005554 204.446930} {517.362671 148.152969} {456.641235 137.074249}} size 60 angle -0.157784} 48605 {id 48605 c {365.335940 265.382087} p {{397.465179 297.087921} {397.123322 241.078461} {331.988190 232.473801} {333.097260 290.030762}} size 56 angle 1.576900} 48607 {id 48607 c {593.918332 292.977820} p {{567.305542 315.167755} {617.385620 319.511688} {620.053650 271.186005} {568.262878 263.969849}} size 50 angle -0.086523} 48608 {id 48608 c {236.291299 366.820416} p {{202.024750 393.381042} {272.369934 397.377472} {269.129639 341.366821} {198.805801 335.071808}} size 70 angle -0.056751} 48610 {id 48610 c {486.311857 383.896561} p {{457.866730 407.818268} {514.040649 410.630219} {514.123901 360.507263} {457.134186 355.766022}} size 56 angle -0.050016} 48613 {id 48613 c {370.907103 480.363625} p {{402.015625 506.210236} {401.381683 455.518799} {338.221100 453.206360} {339.819580 505.708160}} size 50 angle 1.583302} 48615 {id 48615 c {588.610704 483.153853} p {{563.043274 506.112549} {612.937317 506.486633} {613.698975 460.625427} {563.892517 459.445496}} size 49 angle -0.007497} 48616 {id 48616 c {247.747799 583.097366} p {{215.949295 610.146484} {282.119080 607.427429} {278.761658 556.715698} {212.549408 558.181824}} size 66 angle 0.041069} 48618 {id 48618 c {485.557389 575.696389} p {{458.575623 599.804138} {511.779755 597.280396} {512.143311 551.942322} {458.491974 553.418457}} size 53 angle 0.047400}} imageName pose-1781543257841-9.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 271 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-263.442465 -3993.519151 3622.146186 }{3838.120310 362.146076 1127.873075 }{-0.281576 0.033683 0.956437 }} rmse 2.30152949436 tags {48601 {id 48601 c {198.621573 241.319812} p {{222.522720 260.372314} {216.912018 217.634796} {174.017868 221.707275} {181.274582 263.783112}} size 43 angle 1.701333} 48603 {id 48603 c {170.962676 67.695843} p {{197.280319 89.311028} {187.799377 43.787811} {145.962463 47.162689} {153.747971 92.140640}} size 46 angle 1.776127} 48604 {id 48604 c {293.592474 318.039051} p {{317.013885 337.112396} {311.371521 295.126556} {269.805115 298.667694} {276.050354 340.646210}} size 42 angle 1.704383} 48606 {id 48606 c {270.454320 148.843220} p {{295.507935 169.239349} {289.732910 124.954781} {245.201157 128.284637} {251.416473 172.433350}} size 44 angle 1.700472} 48609 {id 48609 c {365.796203 226.761980} p {{389.959595 246.366608} {384.328979 203.366684} {341.377594 206.950287} {347.695770 249.611496}} size 43 angle 1.701000} 48611 {id 48611 c {342.683495 55.350728} p {{366.480438 74.572601} {360.948029 32.722778} {317.286224 34.836197} {324.416443 77.981796}} size 42 angle 1.702231} 48612 {id 48612 c {460.969073 304.179221} p {{484.815125 323.147705} {479.274994 281.422089} {436.590271 284.786957} {443.134369 326.350555}} size 42 angle 1.702800} 48614 {id 48614 c {438.893249 134.686283} p {{463.889557 155.440750} {457.597778 110.989212} {414.331299 114.292465} {420.062805 158.542877}} size 44 angle 1.711405} 48617 {id 48617 c {533.080383 213.173669} p {{557.535583 233.393188} {551.556335 189.925522} {509.016449 193.277649} {514.665344 236.345169}} size 43 angle 1.707495} 48619 {id 48619 c {511.162161 40.181078} p {{535.220459 60.709080} {529.012695 17.277449} {487.738098 20.194244} {492.589447 64.011322}} size 43 angle 1.712767} 48602 {id 48602 c {183.638056 152.018918} p {{209.137878 172.819244} {202.462860 127.247940} {158.109695 131.195312} {165.382980 176.040207}} size 46 angle 1.716236} 48605 {id 48605 c {280.437145 231.136902} p {{261.948456 254.223755} {304.560974 250.985748} {299.074646 207.864227} {256.200226 211.195007}} size 42 angle 0.075841} 48607 {id 48607 c {255.648743 58.022969} p {{280.276367 78.527657} {273.481659 34.840279} {230.918121 37.432526} {237.351044 81.809875}} size 44 angle 1.725090} 48608 {id 48608 c {374.839880 308.191019} p {{398.570862 327.621948} {393.538696 285.166840} {350.828522 288.530518} {356.646088 330.593353}} size 42 angle 1.688775} 48610 {id 48610 c {353.426549 139.437219} p {{378.838562 160.236038} {372.627075 115.518738} {328.744843 119.236130} {334.531097 162.975662}} size 45 angle 1.708819} 48613 {id 48613 c {447.986478 217.436763} p {{429.169769 240.373611} {472.259338 237.322754} {467.006531 194.252045} {423.699921 197.539551}} size 43 angle 0.070685} 48615 {id 48615 c {425.381881 44.997536} p {{449.748932 65.453217} {443.391968 21.960690} {402.644073 25.909575} {406.869446 68.676941}} size 43 angle 1.715931} 48616 {id 48616 c {542.267473 295.145410} p {{565.842590 314.410583} {560.579468 272.551575} {518.264099 275.530273} {524.113098 317.544769}} size 42 angle 1.695874} 48618 {id 48618 c {520.425825 125.529852} p {{545.750671 146.685135} {538.838501 101.829994} {496.323822 105.396080} {501.663605 149.679626}} size 45 angle 1.723693}} imageName pose-1781543257841-10.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 286 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{50.824095 -712.814483 1047.080530 }{1220.638908 279.244176 172.091587 }{-0.050051 0.134620 0.274120 }} rmse 1.70201751052 tags {48601 {id 48601 c {72.271242 414.743317} p {{109.223740 440.646667} {102.671288 390.229553} {35.977558 389.301788} {40.616467 440.268860}} size 50 angle 1.700037} 48603 {id 48603 c {54.034779 217.560069} p {{89.145515 245.273972} {86.687927 196.433075} {16.739708 188.122009} {21.451021 238.642166}} size 48 angle 1.621072} 48604 {id 48604 c {205.449907 509.739067} p {{237.443558 532.384338} {232.669586 485.308655} {172.757889 486.599487} {177.778259 534.575134}} size 47 angle 1.671861} 48606 {id 48606 c {186.127986 322.854836} p {{216.630951 347.064301} {212.562012 302.016602} {154.300674 297.594269} {158.851440 344.357239}} size 45 angle 1.660877} 48609 {id 48609 c {307.253575 416.963510} p {{337.794800 439.960144} {330.584656 395.770905} {277.674011 394.690979} {282.244781 439.680054}} size 44 angle 1.732536} 48611 {id 48611 c {287.998633 243.027042} p {{315.487518 266.903290} {311.848602 224.639084} {259.013916 217.851547} {263.363373 262.020447}} size 42 angle 1.656684} 48612 {id 48612 c {417.887151 502.336126} p {{444.486633 522.683228} {439.543701 480.797607} {390.688629 481.530792} {395.722961 524.379517}} size 42 angle 1.688263} 48614 {id 48614 c {397.370296 335.164383} p {{424.254028 357.527649} {418.144684 316.253967} {370.656311 312.942322} {375.638885 354.945953}} size 41 angle 1.717750} 48617 {id 48617 c {499.446103 419.795104} p {{524.130798 440.142609} {518.483093 400.440186} {474.786102 399.467957} {479.741669 439.828613}} size 40 angle 1.712099} 48619 {id 48619 c {479.151452 262.342380} p {{503.282379 284.006531} {498.348785 245.130402} {454.578003 240.280945} {459.620728 279.853271}} size 39 angle 1.697027} 48600 {id 48600 c {77.699261 512.609928} p {{113.413376 536.890869} {108.199699 486.683990} {41.208942 487.801270} {46.064499 539.500061}} size 50 angle 1.674269} 48605 {id 48605 c {193.944591 415.181222} p {{161.437576 390.916840} {165.369568 439.293060} {226.656128 439.598267} {220.324692 392.921478}} size 48 angle -1.489695} 48607 {id 48607 c {176.552192 230.694903} p {{207.905884 256.611755} {204.110565 210.874542} {143.436234 203.321365} {148.534119 250.845886}} size 45 angle 1.653588} 48608 {id 48608 c {313.934619 506.088315} p {{344.029724 528.150574} {338.209686 483.178070} {283.309875 483.637787} {288.532684 530.062073}} size 45 angle 1.699494} 48610 {id 48610 c {296.282791 329.818533} p {{325.236298 353.672607} {320.333221 310.113373} {267.727356 306.292419} {271.577606 350.060150}} size 43 angle 1.682886} 48613 {id 48613 c {406.646786 419.554464} p {{379.693573 397.918732} {383.775238 440.470154} {433.692444 441.264404} {428.465881 399.601227}} size 42 angle -1.475166} 48615 {id 48615 c {388.513550 253.961729} p {{414.263428 276.515167} {410.385437 236.083435} {362.790558 231.431839} {366.332153 272.093018}} size 40 angle 1.666418} 48616 {id 48616 c {507.837697 501.472006} p {{532.209351 521.014099} {527.509155 481.012390} {482.639832 481.267426} {487.555908 522.566406}} size 40 angle 1.687760} 48618 {id 48618 c {488.165975 341.681269} p {{513.142700 363.443085} {506.917389 323.423706} {463.470276 320.164307} {468.794586 360.542480}} size 40 angle 1.725117}} imageName pose-1781543257841-11.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 310 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{766892.576057 -19515.503279 451640.762142 }{23960.984967 703560.433782 93720.310217 }{49.603996 -23.693156 159.828412 }} rmse 1.83027038725 tags {48601 {id 48601 c {432.038537 553.445692} p {{449.389191 528.153564} {414.490356 532.363770} {415.014954 578.261047} {449.635620 574.586365}} size 35 angle -3.021533} 48603 {id 48603 c {302.262651 569.126614} p {{318.298492 545.140564} {285.711456 548.772949} {287.065430 591.858276} {318.288391 588.834106}} size 32 angle -3.030584} 48604 {id 48604 c {500.794313 450.427968} p {{519.482239 422.830261} {481.857849 429.776672} {483.057526 476.621063} {519.694641 471.039856}} size 38 angle -2.959023} 48606 {id 48606 c {365.341744 472.858152} p {{381.949127 447.837952} {349.402557 453.597107} {349.204224 497.170471} {381.573456 492.472687}} size 33 angle -2.966454} 48609 {id 48609 c {429.053209 371.806219} p {{445.609863 345.667053} {411.475128 352.892456} {412.795074 397.474091} {446.470551 390.547028}} size 34 angle -2.932999} 48611 {id 48611 c {302.674349 398.168756} p {{316.837280 373.322449} {289.007324 380.852509} {288.867432 422.390503} {316.956909 416.264893}} size 28 angle -2.877346} 48612 {id 48612 c {496.276042 264.759201} p {{513.637085 237.214569} {477.861755 246.603622} {479.160706 291.914001} {514.729065 282.952972}} size 36 angle -2.884936} 48614 {id 48614 c {363.212078 299.003323} p {{379.272125 273.819183} {347.609619 282.036316} {347.335876 323.899170} {379.685486 316.917450}} size 32 angle -2.887672} 48617 {id 48617 c {427.922356 195.767095} p {{445.219391 168.574158} {411.057007 178.722443} {411.071198 222.259064} {444.654907 212.677536}} size 35 angle -2.852835} 48619 {id 48619 c {304.872502 233.641435} p {{319.946808 208.123108} {291.097809 217.632965} {290.434784 258.082123} {318.112488 249.028488}} size 30 angle -2.823167} 48600 {id 48600 c {501.221953 543.284653} p {{520.159790 516.529175} {482.061554 521.702759} {482.690491 569.466003} {521.101440 565.676514}} size 38 angle -3.006622} 48602 {id 48602 c {362.055178 560.390636} p {{378.363037 535.925354} {345.495270 539.720520} {345.660431 584.986267} {378.310333 580.680359}} size 33 angle -3.026634} 48605 {id 48605 c {428.911134 460.333650} p {{411.418060 485.897827} {447.390472 480.925568} {447.014984 433.876892} {411.214752 440.614197}} size 36 angle 0.137354} 48607 {id 48607 c {299.170137 480.372077} p {{315.152313 456.267578} {284.449646 461.873840} {283.119354 504.580048} {315.378815 500.740417}} size 31 angle -2.960984} 48608 {id 48608 c {497.456230 354.845126} p {{515.249817 326.969238} {479.143768 336.376831} {479.984161 382.217316} {516.885071 374.439301}} size 37 angle -2.886705} 48610 {id 48610 c {362.066778 384.370008} p {{378.052521 358.907959} {345.932373 365.576324} {346.316467 409.457062} {378.003723 402.933685}} size 32 angle -2.936894} 48613 {id 48613 c {426.550325 281.249530} p {{409.839600 307.328125} {444.106659 299.489532} {443.746246 254.413742} {409.587128 263.625763}} size 35 angle 0.224881} 48616 {id 48616 c {495.222277 174.174471} p {{513.788574 145.978683} {477.288757 157.132172} {477.218567 201.515884} {513.863220 191.889038}} size 38 angle -2.845028} 48618 {id 48618 c {362.450130 213.833265} p {{379.252136 187.789291} {346.920319 197.150696} {346.528229 238.513031} {378.182556 230.733490}} size 33 angle -2.859758}} imageName pose-1781543257841-12.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0536666666666 0.0766666666667} {0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0536666666666 0.168666666667} {0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 336 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{4603.471570 134559.198783 47159.825235 }{-135326.500196 5334.233566 57404.380517 }{-0.661932 0.140649 30.635474 }} rmse 1.34260804628 tags {48601 {id 48601 c {1073.750515 175.041853} p {{1052.528687 157.187790} {1052.229614 193.388962} {1095.322754 193.190720} {1094.947021 156.971298}} size 36 angle -1.579058} 48603 {id 48603 c {1074.066976 324.507615} p {{1052.206787 305.428101} {1052.459229 343.463501} {1096.251709 343.870392} {1096.289062 305.012787}} size 38 angle -1.564159} 48604 {id 48604 c {991.370515 107.495040} p {{971.912415 90.922264} {970.732605 125.059685} {1012.167603 125.208252} {1012.146545 89.812843}} size 34 angle -1.605343} 48606 {id 48606 c {988.277975 249.339919} p {{967.488159 230.941681} {966.608826 267.273804} {1009.637512 268.242340} {1010.369141 231.056763}} size 36 angle -1.594994} 48609 {id 48609 c {907.009210 175.727970} p {{887.060913 157.463745} {885.001831 193.691315} {927.278198 194.285812} {928.883423 157.873322}} size 36 angle -1.627573} 48611 {id 48611 c {899.603721 323.934888} p {{878.815857 303.766144} {877.170288 343.879761} {920.487305 344.196503} {922.151794 303.888092}} size 40 angle -1.611796} 48612 {id 48612 c {829.132043 104.562774} p {{810.125427 86.692841} {807.380005 121.667053} {848.812683 123.066422} {850.246216 87.960068}} size 35 angle -1.649134} 48614 {id 48614 c {818.998538 247.498701} p {{798.753723 228.354401} {796.158691 265.858429} {838.737915 266.165039} {841.599487 229.331009}} size 37 angle -1.639880} 48617 {id 48617 c {741.013150 172.140930} p {{721.825806 153.315475} {717.891663 189.537949} {760.464600 191.225510} {763.652710 155.106522}} size 36 angle -1.678983} 48619 {id 48619 c {725.870029 321.457629} p {{706.293152 301.516876} {702.403625 340.028595} {745.532410 341.485474} {749.751099 302.558502}} size 38 angle -1.671451} 48600 {id 48600 c {1074.052102 105.429277} p {{1053.495850 88.308304} {1053.453979 123.142807} {1095.533203 123.320541} {1094.498901 87.845879}} size 34 angle -1.571998} 48602 {id 48602 c {1075.037272 247.719933} p {{1052.954712 228.852646} {1053.197266 266.806152} {1097.088257 266.560242} {1096.558472 228.912323}} size 37 angle -1.564406} 48605 {id 48605 c {991.462856 176.293567} p {{970.636841 157.802673} {969.213196 195.071320} {1012.382080 194.867218} {1013.173828 157.970444}} size 37 angle -1.608977} 48607 {id 48607 c {988.271297 323.409970} p {{966.160828 303.230164} {965.943604 343.330688} {1010.088562 343.322174} {1010.208191 303.837921}} size 40 angle -1.576213} 48608 {id 48608 c {911.985226 106.559502} p {{891.915039 88.722786} {890.529480 123.506119} {931.588745 123.981483} {933.158203 89.836227}} size 34 angle -1.610609} 48610 {id 48610 c {904.876075 247.834935} p {{884.256775 228.930695} {882.191711 266.480865} {925.678406 266.906982} {927.533142 229.211441}} size 37 angle -1.625736} 48613 {id 48613 c {825.474011 173.685320} p {{805.874146 155.010681} {802.850891 191.792252} {845.849548 193.099014} {848.043945 155.620956}} size 36 angle -1.652807} 48615 {id 48615 c {814.123097 321.664336} p {{793.880493 301.762512} {790.620117 341.099457} {835.070190 342.258789} {837.308655 302.491699}} size 39 angle -1.653491} 48616 {id 48616 c {749.620519 102.389401} p {{730.910706 84.664383} {727.124084 119.449913} {768.818787 120.577164} {771.829041 85.547234}} size 34 angle -1.679226} 48618 {id 48618 c {735.360506 244.450282} p {{715.602051 225.177017} {711.425720 262.848114} {755.005920 263.613281} {758.853516 226.392029}} size 37 angle -1.681208}} imageName pose-1781543257841-13.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 349 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{-42006.056341 618407.989571 46334.318232 }{-565093.723952 -27983.125273 251552.732742 }{26.922105 54.178774 129.547352 }} rmse 0.738898030151 tags {48601 {id 48601 c {1583.305303 145.282432} p {{1553.724854 133.092209} {1563.607910 174.091873} {1613.596924 157.765732} {1603.335205 115.986664}} size 42 angle -1.334257} 48603 {id 48603 c {1623.495857 309.412621} p {{1593.311890 295.631622} {1603.908203 336.235626} {1654.117798 323.393585} {1643.897461 281.475006}} size 41 angle -1.315523} 48604 {id 48604 c {1471.273914 100.575907} p {{1445.189575 90.033272} {1453.117554 128.696182} {1499.084229 111.816139} {1489.562866 72.250275}} size 39 angle -1.368546} 48606 {id 48606 c {1507.686781 256.319445} p {{1479.963989 243.632904} {1489.166260 282.961151} {1535.705322 269.141327} {1526.807739 228.814011}} size 40 angle -1.340945} 48609 {id 48609 c {1401.802316 207.969095} p {{1376.445190 196.288300} {1384.526978 234.246750} {1427.940308 220.009598} {1419.446411 181.130524}} size 38 angle -1.361017} 48611 {id 48611 c {1435.122709 360.461753} p {{1409.137939 346.993469} {1417.652100 385.808502} {1461.908081 374.345001} {1452.723511 334.926117}} size 39 angle -1.354864} 48612 {id 48612 c {1304.792060 163.544640} p {{1281.339722 152.543762} {1288.938965 189.175308} {1328.660156 174.740540} {1320.708984 137.810776}} size 37 angle -1.366247} 48614 {id 48614 c {1335.437698 309.322675} p {{1311.624146 297.276917} {1319.497681 333.455688} {1359.369629 321.428314} {1351.731812 284.653564}} size 37 angle -1.356509} 48617 {id 48617 c {1243.749759 262.137148} p {{1221.931274 250.747498} {1228.881592 285.992737} {1265.767822 273.630981} {1258.832153 237.937836}} size 35 angle -1.376096} 48619 {id 48619 c {1272.913442 404.925019} p {{1250.692993 392.101196} {1257.740112 428.166321} {1295.694092 418.072144} {1288.293701 381.366760}} size 36 angle -1.377828} 48600 {id 48600 c {1564.066360 65.587149} p {{1535.401978 54.913307} {1544.859375 94.562202} {1593.631592 76.596443} {1583.183472 36.747677}} size 40 angle -1.336643} 48602 {id 48602 c {1603.038917 226.582457} p {{1572.679565 213.412918} {1582.847534 254.925323} {1633.826782 239.937881} {1623.557983 197.779617}} size 42 angle -1.330587} 48605 {id 48605 c {1488.559622 178.892756} p {{1469.938721 206.515533} {1516.978638 191.118256} {1507.937988 150.146332} {1460.885254 166.987595}} size 49 angle 0.316332} 48607 {id 48607 c {1526.241290 334.702058} p {{1498.980103 321.365814} {1506.401367 362.501465} {1555.100708 348.820160} {1545.040161 308.361359}} size 41 angle -1.392307} 48608 {id 48608 c {1384.624545 133.919279} p {{1359.451660 122.670517} {1367.424805 161.219101} {1410.523193 145.492355} {1401.587036 106.996025}} size 39 angle -1.366839} 48610 {id 48610 c {1417.455410 284.507754} p {{1391.823120 272.121887} {1400.070435 310.095215} {1443.510010 297.097687} {1435.313721 258.223633}} size 38 angle -1.356931} 48613 {id 48613 c {1319.617852 236.336932} p {{1303.319336 261.778351} {1343.896973 248.560242} {1336.254272 210.368057} {1295.936890 224.414764}} size 42 angle 0.314909} 48615 {id 48615 c {1350.581998 384.136254} p {{1326.474976 370.715607} {1334.264893 408.357025} {1375.247803 397.867981} {1367.291260 359.333374}} size 38 angle -1.366726} 48616 {id 48616 c {1229.578846 191.805533} p {{1207.622070 180.703964} {1214.551758 216.823944} {1252.010010 203.146957} {1244.745361 166.554993}} size 36 angle -1.381248} 48618 {id 48618 c {1258.106145 333.438437} p {{1236.033203 321.214142} {1243.164917 356.981049} {1280.836792 346.026978} {1273.311035 309.480377}} size 36 angle -1.373983}} imageName pose-1781543257841-14.jpeg} {model {48600 {c {0.0191666666667 0.0191666666667} p {{0.00766666666666 0.0306666666667} {0.0306666666667 0.0306666666667} {0.0306666666667 0.00766666666667} {0.00766666666666 0.00766666666667}}} 48601 {c {0.0651666666666 0.0191666666667} p {{0.0536666666666 0.0306666666667} {0.0766666666667 0.0306666666667} {0.0766666666667 0.00766666666667} {0.0536666666666 0.00766666666667}}} 48602 {c {0.111166666667 0.0191666666667} p {{0.0996666666666 0.0306666666667} {0.122666666667 0.0306666666667} {0.122666666667 0.00766666666667} {0.0996666666666 0.00766666666667}}} 48603 {c {0.157166666667 0.0191666666667} p {{0.145666666667 0.0306666666667} {0.168666666667 0.0306666666667} {0.168666666667 0.00766666666667} {0.145666666667 0.00766666666667}}} 48604 {c {0.0191666666667 0.0651666666667} p {{0.00766666666666 0.0766666666667} {0.0306666666667 0.0766666666667} {0.0306666666667 0.0536666666667} {0.00766666666666 0.0536666666667}}} 48605 {c {0.0651666666666 0.0651666666667} p {{0.0766666666667 0.0766666666667} {0.0766666666667 0.0536666666667} {0.0536666666666 0.0536666666667} {0.0536666666666 0.0766666666667}}} 48606 {c {0.111166666667 0.0651666666667} p {{0.0996666666666 0.0766666666667} {0.122666666667 0.0766666666667} {0.122666666667 0.0536666666667} {0.0996666666666 0.0536666666667}}} 48607 {c {0.157166666667 0.0651666666667} p {{0.145666666667 0.0766666666667} {0.168666666667 0.0766666666667} {0.168666666667 0.0536666666667} {0.145666666667 0.0536666666667}}} 48608 {c {0.0191666666667 0.111166666667} p {{0.00766666666666 0.122666666667} {0.0306666666667 0.122666666667} {0.0306666666667 0.0996666666667} {0.00766666666666 0.0996666666667}}} 48609 {c {0.0651666666666 0.111166666667} p {{0.0536666666666 0.122666666667} {0.0766666666667 0.122666666667} {0.0766666666667 0.0996666666667} {0.0536666666666 0.0996666666667}}} 48610 {c {0.111166666667 0.111166666667} p {{0.0996666666666 0.122666666667} {0.122666666667 0.122666666667} {0.122666666667 0.0996666666667} {0.0996666666666 0.0996666666667}}} 48611 {c {0.157166666667 0.111166666667} p {{0.145666666667 0.122666666667} {0.168666666667 0.122666666667} {0.168666666667 0.0996666666667} {0.145666666667 0.0996666666667}}} 48612 {c {0.0191666666667 0.157166666667} p {{0.00766666666666 0.168666666667} {0.0306666666667 0.168666666667} {0.0306666666667 0.145666666667} {0.00766666666666 0.145666666667}}} 48613 {c {0.0651666666666 0.157166666667} p {{0.0766666666667 0.168666666667} {0.0766666666667 0.145666666667} {0.0536666666666 0.145666666667} {0.0536666666666 0.168666666667}}} 48614 {c {0.111166666667 0.157166666667} p {{0.0996666666666 0.168666666667} {0.122666666667 0.168666666667} {0.122666666667 0.145666666667} {0.0996666666666 0.145666666667}}} 48615 {c {0.157166666667 0.157166666667} p {{0.145666666667 0.168666666667} {0.168666666667 0.168666666667} {0.168666666667 0.145666666667} {0.145666666667 0.145666666667}}} 48616 {c {0.0191666666667 0.203166666667} p {{0.00766666666666 0.214666666667} {0.0306666666667 0.214666666667} {0.0306666666667 0.191666666667} {0.00766666666666 0.191666666667}}} 48617 {c {0.0651666666666 0.203166666667} p {{0.0536666666666 0.214666666667} {0.0766666666667 0.214666666667} {0.0766666666667 0.191666666667} {0.0536666666666 0.191666666667}}} 48618 {c {0.111166666667 0.203166666667} p {{0.0996666666666 0.214666666667} {0.122666666667 0.214666666667} {0.122666666667 0.191666666667} {0.0996666666666 0.191666666667}}} 48619 {c {0.157166666667 0.203166666667} p {{0.145666666667 0.214666666667} {0.168666666667 0.214666666667} {0.168666666667 0.191666666667} {0.145666666667 0.191666666667}}}} version 365 camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 cameraWidth 1920 cameraHeight 1080 display monitor displayWidth 4096 displayHeight 2160 tagSize 0.023 H_modelToDisplay {{118.010597 523.486690 123.680915 }{-432.421027 -2.562325 118.592818 }{0.057790 0.000156 0.105660 }} rmse 2.62738649114 tags {48601 {id 48601 c {1281.823051 416.293377} p {{1255.699829 388.136688} {1251.023804 445.529541} {1307.392212 443.852875} {1312.758667 386.927765}} size 57 angle -1.652091} 48603 {id 48603 c {1264.215471 625.949442} p {{1239.727051 601.371399} {1236.684692 651.069885} {1287.757080 649.577209} {1292.405151 600.227783}} size 49 angle -1.631936} 48604 {id 48604 c {1175.547137 301.716312} p {{1147.258789 271.473053} {1145.182251 332.074463} {1202.905884 330.965729} {1206.824707 270.445679}} size 60 angle -1.605048} 48606 {id 48606 c {1164.071816 527.257960} p {{1137.674683 501.254913} {1135.616333 553.908508} {1189.954102 552.753845} {1193.525513 499.672516}} size 52 angle -1.609869} 48609 {id 48609 c {1057.691902 421.647838} p {{1029.636353 393.476013} {1029.013062 450.735626} {1085.340820 449.411346} {1086.356323 392.574677}} size 57 angle -1.581681} 48611 {id 48611 c {1055.267679 630.006316} p {{1029.088501 606.413452} {1028.922974 654.209473} {1080.769531 652.988770} {1082.065674 605.386719}} size 47 angle -1.574260} 48612 {id 48612 c {941.851845 306.657821} p {{911.075012 276.230469} {913.477234 337.421875} {971.420471 335.890686} {970.827820 275.241760}} size 61 angle -1.531559} 48614 {id 48614 c {947.986269 532.219138} p {{919.149841 505.999939} {921.341370 559.041992} {976.093506 557.775330} {975.236938 504.786469}} size 53 angle -1.529503} 48617 {id 48617 c {831.572637 426.604688} p {{800.865417 398.153564} {804.965332 455.394958} {862.442871 455.206848} {858.715637 397.234772}} size 57 angle -1.499293} 48619 {id 48619 c {845.324096 635.250848} p {{817.130249 611.342651} {820.856201 659.968567} {873.256470 658.937317} {870.209106 610.111755}} size 48 angle -1.494321} 48600 {id 48600 c {1289.225731 301.078433} p {{1262.005249 271.153259} {1257.411865 331.515289} {1315.754639 330.243317} {1321.734985 269.976288}} size 60 angle -1.646747} 48602 {id 48602 c {1269.351394 526.065227} p {{1243.669922 499.388092} {1239.410889 552.759949} {1294.399414 552.084351} {1299.760132 498.953033}} size 53 angle -1.650427} 48605 {id 48605 c {1166.059282 420.908325} p {{1135.966187 449.677094} {1193.038208 449.324493} {1196.572510 391.737915} {1138.996216 392.403534}} size 57 angle 0.006178} 48607 {id 48607 c {1156.044488 628.905614} p {{1131.020508 604.596680} {1127.738647 654.367432} {1180.689087 652.846008} {1184.045410 603.718079}} size 49 angle -1.636641} 48608 {id 48608 c {1056.293758 306.447613} p {{1026.432983 275.976837} {1026.088135 337.427277} {1084.479858 335.209503} {1086.134399 275.842285}} size 61 angle -1.576408} 48610 {id 48610 c {1052.519235 531.044210} p {{1024.884399 504.723969} {1024.794189 557.831543} {1079.799805 557.027039} {1081.060059 503.468689}} size 53 angle -1.572495} 48613 {id 48613 c {941.894180 424.599430} p {{913.944580 453.659027} {971.480835 453.366516} {970.402649 394.958771} {912.237305 395.764069}} size 57 angle 0.005084} 48615 {id 48615 c {946.671222 633.710593} p {{919.646973 609.295410} {920.405457 659.232544} {972.941345 657.444458} {972.740173 608.379883}} size 49 angle -1.555609} 48616 {id 48616 c {821.401493 308.099298} p {{789.459595 276.949677} {793.619507 339.280548} {853.132202 339.042969} {849.147522 276.958405}} size 62 angle -1.504156} 48618 {id 48618 c {835.587154 535.015310} p {{806.015076 508.322021} {809.567627 561.604919} {864.443115 561.062195} {862.566467 507.444885}} size 53 angle -1.504221}} imageName pose-1781543257841-15.jpeg}}
builtin-programs/calibrate/calibrate.folk claims the calibration measurements are {tagSideLength 23mm (
[ m924:0 (s1604:0 s1605:0) ]
)builtin-programs/calibrate/calibrate.folk claims the calibration measurements are {tagSideLength 23mm left 13mm top 16mm bottom 16mm}
builtin-programs/calibrate/calibrate.folk claims a calibration from camera /dev/v4l/by-path/pci-0000: (
[ m921:0 (s1599:0 s1600:0 s1601:0) ]
[ m922:0 () ]
[ m1066:0 (s1855:0) ]
[ m1067:0 () ]
[ m4498:0 () ]
[ m23662:0 () ]
)builtin-programs/calibrate/calibrate.folk claims a calibration from camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to display monitor is {camera {name /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 intrinsics {width 1920 height 1080 fx 1013.037163 fy 1015.05071542 cx 986.505709454 cy 545.513675376 s 0.0 k1 0.0503748054324 k2 -0.0383457623661 p1 -0.0058226268105 p2 0.00403722808602} extrinsics {{R {{0.994667945026 0.0197134959591 0.101227749236} {-0.0340129642422 0.989347574535 0.141543262024} {-0.0973591156578 -0.144231601385 0.984742833312}} t {0.191359486175 -0.12619473889 0.669866199596}} {R {{0.996477902647 0.0606262958815 0.0579330802135} {-0.0657285737939 0.993710702102 0.0906575706414} {-0.0520724891123 -0.0941461245898 0.994195636232}} t {0.183819069877 -0.215713560339 0.636000328977}} {R {{0.99807275522 0.0487141804752 -0.0384409144984} {-0.0553462285699 0.97895705889 -0.196417595529} {0.0280636824013 0.198166610384 0.979766515176}} t {0.152204455868 -0.219379425659 0.428755691804}} {R {{-0.0984088295717 0.994411522015 0.0382286168451} {-0.985519221464 -0.102715339526 0.134912650076} {0.13808535906 -0.0243984407224 0.990119765333}} t {0.0832183545347 -0.0332088811256 0.460897089719}} {R {{-0.0275414576851 0.999594462536 -0.00723730440735} {-0.945927419815 -0.0284023466067 -0.32313251639} {-0.323207030477 -0.00205357584232 0.946326052836}} t {0.0668716664002 0.0826855905467 0.58063618542}} {R {{0.977631943359 0.118616473249 0.173683377439} {-0.141681198338 0.981728011298 0.127029720422} {-0.155442019295 -0.148795981487 0.976574387607}} t {-0.071499269077 -0.245536619321 0.646007477281}} {R {{0.994631520402 0.0463641076387 -0.0925122053818} {-0.0804067698935 0.909026847489 -0.408907008866} {0.0651374698389 0.414150407542 0.907874743539}} t {-0.0625721272925 -0.247526255705 0.494089361383}} {R {{0.989765148115 0.0974175726236 0.104282156289} {-0.140833832775 0.784769834278 0.603574468275} {-0.0230387309124 -0.612083428751 0.790457521393}} t {-0.0883455357981 -0.136403511085 0.598724880532}} {R {{0.958968184674 0.143241922485 -0.244666655729} {-0.112179896454 0.984260366685 0.136554756067} {0.260376058067 -0.103504986429 0.959943241119}} t {-0.221743275803 -0.197167435237 0.451850197514}} {R {{0.829940075548 -0.122917361048 -0.544142254702} {-0.0234268595039 0.966883052634 -0.254142371088} {0.557360433878 0.223670482812 0.799575426002}} t {-0.30941531861 -0.178454854533 0.383463252602}} {R {{-0.0952651290049 0.994493623527 -0.0436690732537} {-0.993664652552 -0.0976301444883 -0.0556678826357} {-0.0596247722479 0.0380892064811 0.997493909197}} t {-0.450833902525 -0.100913664361 0.569854730921}} {R {{-0.13222900895 0.771757444697 -0.622017632987} {-0.989426728614 -0.0650447900434 0.129629950218} {0.0595838727943 0.632581711594 0.772198251915}} t {-0.429269829389 0.00738784910002 0.453945458336}} {R {{-0.931893226723 -0.0633411596506 0.357159504257} {0.101517499857 -0.990830614295 0.0891565533175} {0.348237291527 0.119342328077 0.929778574455}} t {-0.213782883651 0.0163606705727 0.478773255314}} {R {{-0.0171628028943 -0.999831313267 0.00654088741224} {0.949702055704 -0.0142557663666 0.312830271103} {-0.312684255424 0.0115809385039 0.949786522475}} t {0.0686153329494 -0.264848272146 0.585711717308}} {R {{0.174959816484 -0.878501858551 0.444548700525} {0.978010274707 0.207124517871 0.024399521821} {-0.113511960534 0.43050426086 0.895422311648}} t {0.327420003853 -0.282021660069 0.560740017671}} {R {{0.00734455470441 -0.999129363624 -0.0410678981626} {0.952715381632 0.0194676431507 -0.303239859636} {0.30377534317 -0.036898856533 0.952028894135}} t {0.138303921334 -0.114296329757 0.399637470803}}} rmse 1.00882933419} projector {name monitor intrinsics {width 4096 height 2160 fx 5213.39604688 fy 5190.26370373 cx 1792.05592395 cy -83.5894167525 s 0.0 k1 -0.00229328944071 k2 -0.0183385876335 p1 0.00176316743657 p2 -0.0101564863249} extrinsics {{R {{-0.99768119486 0.00197733833236 -0.0680317834285} {-0.01248017632 -0.987944224525 0.154306365475} {-0.0669064916309 0.154797607734 0.985678051909}} t {-0.172574663164 0.335985961584 1.3071506675}} {R {{-0.998621271079 -0.0374486191288 -0.0367852942736} {0.0285942637324 -0.975736236246 0.217074101076} {-0.0440218699177 0.215722966329 0.975461776168}} t {-0.168441420389 0.411566728856 1.2448951123}} {R {{-0.999021038004 -0.023176144349 0.0376806576103} {0.0388434584052 -0.867181411032 0.496475161614} {0.0211695858238 0.497452778356 0.867232714988}} t {-0.140063939335 0.351895144522 1.04792155432}} {R {{0.0736124534861 -0.997184597184 -0.0142858612312} {0.982627764783 0.0700759231908 0.171848889626} {-0.170363970864 -0.0266879022838 0.985019732443}} t {-0.0668216134487 0.187568738404 1.13411922804}} {R {{0.00258995212001 -0.999972272943 0.00698179720783} {0.805450913039 0.00622387301266 0.59262980864} {-0.592656830579 0.00408861210629 0.805444699789}} t {-0.0459039181232 0.113063060066 1.28760701808}} {R {{-0.98412668136 -0.094607722342 -0.150146774553} {0.0678072751382 -0.982315977285 0.174520755809} {-0.164002586789 0.16156948859 0.97313845463}} t {0.0857586737586 0.448926853048 1.24716090584}} {R {{-0.996762037738 -0.0144577479405 0.0790974945825} {0.0630663167159 -0.750804176201 0.657507208093} {0.0498806557759 0.660366612211 0.749284897522}} t {0.0740673912735 0.40883129955 1.10529007376}} {R {{-0.993691998287 -0.0860788832653 -0.0718793321839} {0.10496553696 -0.93954483386 -0.325941315604} {-0.0394771907574 -0.331430129926 0.94265349964}} t {0.10463146415 0.331011709205 1.22851499957}} {R {{-0.955688886234 -0.111701582659 0.27236282632} {0.165852263439 -0.968705328304 0.184670012802} {0.243211388389 0.221659070077 0.944306876609}} t {0.232896363468 0.346255273557 1.06994254562}} {R {{-0.814563890505 0.155373456245 0.558878123905} {0.179772345225 -0.848406927302 0.497883108368} {0.551513891192 0.506028432798 0.663149796818}} t {0.31875171455 0.308343633701 1.00744498892}} {R {{0.0573325354068 -0.995045669627 0.0812225075993} {0.918862429155 0.0844056612321 0.385444575313} {-0.390390595007 0.0525337958731 0.919149271674}} t {0.467122942673 0.295571002324 1.20491550989}} {R {{0.106858718067 -0.755493631394 0.646382694149} {0.963247946369 0.239799353576 0.121035795695} {-0.246443925039 0.609693072739 0.753352340452}} t {0.444170133371 0.155441857551 1.12757309117}} {R {{0.947580189673 0.030940622631 -0.318016449276} {0.0339310676981 0.979928043887 0.196442641627} {0.317711294706 -0.196935793282 0.927510553331}} t {0.232747381199 0.151143961339 1.16550254835}} {R {{0.0381449183143 0.999063191721 0.0204378118851} {-0.999253513824 0.0380110876671 0.00689726940511} {0.00611394452673 -0.0206856511191 0.999767334694}} t {-0.0559668268414 0.446592630878 1.18682818074}} {R {{-0.153241510514 0.876172663932 -0.456988514552} {-0.965255711983 -0.0336670843884 0.259129191545} {0.211656443176 0.480820122713 0.85088986341}} t {-0.31231392133 0.446201446672 1.15117952138}} {R {{0.0247204223064 0.998134997428 0.0558160159058} {-0.81825897834 -0.0118734147104 0.574727123416} {0.574317982557 -0.0598794533515 0.816439407415}} t {-0.124889151728 0.244750106882 1.05822439887}}} rmse 0.549329201207} R_cameraToProjector {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} t_cameraToProjector {0.00950987780512 0.0157209796983 0.70557852591} rmse 1.13793057805}
builtin-programs/gpu/gpu.folk claims the GPU Vulkan handle type definer is {apply \{fn\ envStack\ arg (
[ m737:0 (s1136:0) ]
[ m744:0 (s1146:0) ]
[ m771:0 (s18539:0) ]
[ m898:0 (s1394:0) ]
[ m2257:0 (s3352:0) ]
)builtin-programs/gpu/gpu.folk claims the GPU Vulkan handle type definer is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}} {{this builtin-programs/gpu/gpu.folk} {} {^defineVulkanHandleType {{cc type} {
$cc argtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%p", &$argname);
#else
%s $argname; sscanf(Jim_String($obj), "(%s) 0x%%llx", &$argname);
#endif
} $type $type $type $type]
# Tcl_ObjPrintf doesn't work with %lld/%llx for some reason,
# so we do it by hand.
$cc rtype $type [format {
#ifdef VK_USE_64_BIT_PTR_DEFINES
$robj = Jim_ObjPrintf("(%s) 0x%%" PRIxPTR, (uintptr_t) $rvalue);
#else
{
char buf[100]; snprintf(buf, 100, "(%s) 0x%%llx", $rvalue);
$robj = Jim_NewStringObj(buf, -1);
}
#endif
} $type $type]
} {builtin-programs/gpu/gpu.folk 11}}}}}
builtin-programs/gpu/gpu.folk claims the GPU library is <C:cfileog6zwp> (
[ m2249:0 (s3346:0) ]
[ m2250:0 (s3344:0) ]
[ m2252:0 (s3348:0) ]
[ m2251:0 (s3349:0) ]
[ m2253:0 (s3347:0) ]
)builtin-programs/gpu/gpu.folk claims the GPU library is <C:cfileog6zwp>
builtin-programs/gpu/gpu.folk claims the GPU physical device is {(VkPhysicalDevice) 0x79d19d5575f0} ()builtin-programs/gpu/gpu.folk claims the GPU physical device is {(VkPhysicalDevice) 0x79d19d5575f0}
builtin-programs/gpu/gpu.folk claims the GPU device is {(VkDevice) 0x79d19d5898c0} ()builtin-programs/gpu/gpu.folk claims the GPU device is {(VkDevice) 0x79d19d5898c0}
builtin-programs/web/threads.folk wishes the web server handles route /threads with handler {applyBlo (
[ m757:0 () ]
)builtin-programs/web/threads.folk wishes the web server handles route /threads with handler {applyBlock \n\ \ \ \ set\ pid\ \[pid\]\n\ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[glob\ -tails\ -directory\ /proc/\$pid/task\ *\]\n\n\ \ \ \ \ \ \ \ set\ userStacks\ \[dict\ create\]\n\n\ \ \ \ \ \ \ \ set\ euStackOutput\ \[exec\ eu-stack\ --pid=\[pid\]\ --verbose\]\n\ \ \ \ \ \ \ \ set\ currentTid\ none\n\ \ \ \ \ \ \ \ foreach\ line\ \[split\ \$euStackOutput\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[regexp\ \{TID\ (\[0-9\]+):\}\ \$line\ ->\ tid\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ currentTid\ \$tid\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ userStacks\ \$currentTid\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[dict\ getdef\ \$userStacks\ \$currentTid\ \{\}\]\\n\$line\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ set\ tids\ \[\$threadMonitorLib\ workerTids\]\n\ \ \ \ \}\n\n\ \ \ \ set\ totalAllocsMinusFrees\ 0.0\n\ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ <link\ rel=\"stylesheet\"\ href=\"/style.css\">\n\ \ \ \ \ \ \ \ <title>Threads</title>\n\ \ \ \ \ \ \ \ </head>\n\n\ \ \ \ \ \ \ \ <body>\n\n\ \ \ \ \ \ \ \ <h2>Threads</h2>\n\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ tid\ \$tids\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ taskdir\ /proc/\$pid/task/\$tid\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ statusFd\ \[open\ \$taskdir/status\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \[read\ \$statusFd\]\;\ close\ \$statusFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ status\ \"<status\ unknown>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ workerInfo\ \[\$threadMonitorLib\ workerInfoFromTid\ \$tid\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \[dict\ get\ \$userStacks\ \$tid\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ userStack\ \"<not\ found>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ stackFd\ \[open\ \$taskdir/stack\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \[read\ \$stackFd\]\;\ close\ \$stackFd\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ kernelStack\ \"<not\ permitted>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ allocs\ \[dict\ getdef\ \$workerInfo\ _allocs\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ frees\ \[dict\ getdef\ \$workerInfo\ _frees\ -1\]\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{<li\ style=\"\[expr\ \{\$workerInfo\ eq\ \"\"\ ?\ \"color:\ gray\"\ :\ \"\"\}\]\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$taskdir:\ \[regexp\ -inline\ \{State:\[^\\n\]*\\n\}\ \$status\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$workerInfo(isDeactivated)\ ?\ \"(deactivated)\"\ :\ \"(active)\"\}\]<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$workerInfo\ eq\ \"\"\}\ \{subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (Not\ a\ Folk\ worker\ thread)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ totalAllocsMinusFrees\ \[expr\ \{\$totalAllocsMinusFrees\ +\ (\$allocs\ -\ \$frees)\}\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ workQueue\ \[dict\ get\ \$workerInfo\ workQueue\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"allocs\ -\ frees:\ %.2f\ MB\"\ \[expr\ \{(\$allocs\ -\ \$frees)\ /\ 1000000.0\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\[format\ \"allocs:\ %.2f\ MB\"\ \[/\ \$allocs\ 1000000.0\]\]\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[format\ \"frees:\ %.2f\ MB\"\ \[/\ \$frees\ 1000000.0\]\])<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[htmlEscape\ \[dict\ get\ \$workerInfo\ op\]\]\ (elapsed:\ \[dict\ get\ \$workerInfo\ elapsed\]\ us)<br>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Work\ queue\ (\[llength\ \$workQueue\]\ items):</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\[htmlEscape\ \[join\ \$workQueue\ \"\\n\"\]\]</pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>User\ stack:</summary><pre>\[htmlEscape\ \$userStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <details><summary>Kernel\ stack:</summary><pre>\[htmlEscape\ \$kernelStack\]</pre></details>\n\ \ \ \ \ \ \ \ \ \ \ \ </li>\}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ <p>Total\ allocs\ -\ frees:\ \[format\ \"%.2f\ MB\"\ \[expr\ \{\$totalAllocsMinusFrees\ /\ 1000000.0\}\]\]</p>\n\n\ \ \ \ \ \ \ \ <h2>Global\ workqueue\ (\[\$threadMonitorLib\ globalWorkQueueAvailable\])</h2>\n\ \ \ \ \ \ \ \ <ol\ start=\"0\">\n\ \ \ \ \ \ \ \ \[lmap\ item\ \[\$threadMonitorLib\ globalWorkQueueItems\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\ <li>\$item</li>\ \}\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ </ol>\n\n\ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ </html>\n\ \ \ \ \}\]\n {{this builtin-programs/web/threads.folk} {} {threadMonitorLib <C:cfileUfFKg0>}}}
builtin-programs/camera/enumerate.folk claims folk-sva has camera /dev/v4l/by-path/pci-0000:03:00.4-u (
[ m61875:969 () ]
)builtin-programs/camera/enumerate.folk claims folk-sva has camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 with card {NexiGo HD Webcam: NexiGo HD Web} formats {{fourcc {MJPG} description {Motion-JPEG} resolutions {{width 640 height 480 framerates {60.0 30.0}} {width 1600 height 896 framerates {60.0 30.0}} {width 1280 height 720 framerates {60.0 30.0}} {width 1024 height 768 framerates {60.0 30.0}} {width 1024 height 576 framerates {60.0 30.0}} {width 960 height 544 framerates {60.0 30.0}} {width 864 height 480 framerates {60.0 30.0}} {width 848 height 480 framerates {60.0 30.0}} {width 800 height 448 framerates {60.0 30.0}} {width 640 height 360 framerates {60.0 30.0}} {width 352 height 288 framerates {60.0 30.0}} {width 320 height 240 framerates {60.0 30.0}} {width 1920 height 1080 framerates {60.0 30.0}}}} {fourcc {YUYV} description {YUYV 4:2:2} resolutions {{width 640 height 480 framerates {30.0}} {width 1600 height 896 framerates {5.0}} {width 1280 height 720 framerates {10.0 5.0}} {width 1024 height 768 framerates {10.0 5.0}} {width 1024 height 576 framerates {10.0 5.0}} {width 960 height 544 framerates {10.0 5.0}} {width 864 height 480 framerates {10.0 5.0}} {width 848 height 480 framerates {10.0 5.0}} {width 800 height 448 framerates {10.0 5.0}} {width 640 height 360 framerates {30.0}} {width 352 height 288 framerates {30.0}} {width 320 height 240 framerates {30.0}} {width 1920 height 1080 framerates {5.0}}}}}
builtin-programs/camera/enumerate.folk claims folk-sva has camera /dev/v4l/by-path/pci-0000:03:00.4-u (
[ m61882:1055 () ]
)builtin-programs/camera/enumerate.folk claims folk-sva has camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index1 with card {NexiGo HD Webcam: NexiGo HD Web} formats {}
builtin-programs/editor/editor-utils.folk claims the editor utils library is <library:/tmp/editorUtil (
[ m802:0 (s1233:0) ]
[ m829:0 (s1275:0 s1276:0 s1277:0 s1278:0 s1279:0 s1280:0) ]
)builtin-programs/editor/editor-utils.folk claims the editor utils library is <library:/tmp/editorUtilsLib_YaXWyk.tcl>
builtin-programs/saving/saving.folk claims the program save directory is /home/folk/folk-data/program (
[ m828:0 (s1274:0) ]
[ m830:0 (s1281:0) ]
[ m841:0 (s1295:0) ]
[ m939:0 (s1820:0 s1822:0 s1825:0 s1826:0 s1827:0 s1829:0) ]
[ m1044:0 (s1828:0) ]
)builtin-programs/saving/saving.folk claims the program save directory is /home/folk/folk-data/program
builtin-programs/saving/saving.folk claims the hold save directory is /home/folk/folk-data/hold (
[ m839:0 (s1293:0) ]
[ m917:0 (s1561:0 s1562:0) ]
)builtin-programs/saving/saving.folk claims the hold save directory is /home/folk/folk-data/hold
builtin-programs/saving/saving.folk wishes to deserialize namespace hold with directory /home/folk/fo (
[ m920:0 (s1598:0) ]
)builtin-programs/saving/saving.folk wishes to deserialize namespace hold with directory /home/folk/folk-data/hold
builtin-programs/saving/saving.folk wishes to deserialize namespace program with directory /home/folk ()builtin-programs/saving/saving.folk wishes to deserialize namespace program with directory /home/folk/folk-data/program
builtin-programs/web/trie-graph.folk wishes the web server handles route {/trie-graph\.pdf} with hand (
[ m848:0 () ]
)builtin-programs/web/trie-graph.folk wishes the web server handles route {/trie-graph\.pdf} with handler {applyBlock \n\ \ \ \ set\ trie\ \[\]\n\ \ \ \ set\ dot\ \[apply\ \$trieDotify\ \$trieLib\ \[\$trieLib\ dbTrieTclify\]\]\n\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n {{this builtin-programs/web/trie-graph.folk} {} {trieDotify {{trieLib tclifiedTrie} {
local proc idify {word} {
# generate id-able word by eliminating all non-alphanumeric
regsub -all {\W+} $word "_"
}
local proc labelify {word} {
# shorten the longest lines
set word [join [lmap line [split $word "\n"] {
expr { [string length $line] > 80 ? "[string range $line 0 80]..." : $line }
}] "\n"]
string map {"\"" "\\\""} [string map {"\\" "\\\\"} $word]
}
local proc subdot {subtrie} {
set branches [lassign $subtrie ptr key id]
set dot [list]
lappend dot "$ptr \[label=\"[labelify $key]\"\];"
foreach branch $branches {
if {$branch eq {}} continue
set branchptr [lindex $branch 0]
lappend dot "$ptr -> $branchptr;"
lappend dot [subdot $branch]
}
return [join $dot "\n"]
}
return "digraph { rankdir=LR; [subdot $tclifiedTrie] }"
}} getDotAsPdf {{dot} {
set fd [open |[list dot -Tpdf <<$dot] rb]
set response [read $fd]
try {
close $fd
return $response
} on error e {
if {[catch {exec which dot}]} {
error "graphviz not installed!"
}
}
}} trieLib <C:cfileUen4B3>}}}
builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function rotate {{vec2 v float a} vec2 {
(
[ m23443:0 (s30978:0) ]
)builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function rotate {{vec2 v float a} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function wedge2d {{vec2 v vec2 w} float {
(
[ m23444:0 (s30977:0) ]
)builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function wedge2d {{vec2 v vec2 w} float {
return v.x * w.y - v.y * w.x;
}}
builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function invBilinear {
{vec2 pos vec2 (
[ m23446:0 (s30979:0) ]
)builtin-programs/gpu/gpu-fns.folk wishes the GPU compiles function invBilinear {
{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0 fn wedge2d} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
builtin-programs/shapes/region.folk claims builtin-programs/shapes/region.folk has demo \n\ \ #\ How\ ()builtin-programs/shapes/region.folk claims builtin-programs/shapes/region.folk has demo \n\ \ #\ How\ to\ use\n\ \ #\ When\ builtin-programs/shapes/region.folk\ has\ demo\ /code/\ &\ \\\n\ \ #\ \ \ \ \ \$this\ has\ region\ /r/\ \{\n\ \ #\ \ \ \ \ Claim\ \$this\ has\ program\ code\ \$code\n\ \ #\ \ \ \ \ set\ angle\ \[region\ angle\ \$r\]\n\ \ #\ \ \ \ \ set\ pos\ \[region\ bottom\ \$r\]\n\ \ #\ \ \ \ \ Wish\ to\ draw\ text\ with\ position\ \$pos\ scale\ 0.6\ text\ \$code\ radians\ \$angle\ anchor\ topright\n\ \ #\ \}\n\n\ \ When\ \$this\ has\ region\ /r/\ \{\n\ \ \ \ Wish\ region\ \$r\ has\ highlight\ true\ with\ color\ yellow\ thickness\ 1\ dashed\ true\n\n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 0\ width\ 50\ height\ 50\ offset\ \[list\ -250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 0\"\ with\ offset\ \[list\ -250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \ \ Wish\ \$this\ adds\ region\ with\ index\ 1\ width\ 50\ height\ 50\ offset\ \[list\ 250\ 0\]\ highlight\ true\ color\ yellow\n\ \ \ \ Wish\ \$this\ draws\ text\ \"Region\ 1\"\ with\ offset\ \[list\ 250\ -50\]\ scale\ 0.6\ color\ yellow\ \n\ \ \}\n
builtin-programs/display/arc.folk wishes the GPU compiles pipeline arc {{vec2 center float start floa (
[ m23546:0 (s36521:0) ]
)builtin-programs/display/arc.folk wishes the GPU compiles pipeline arc {{vec2 center float start float arclen float radius float thickness vec4 color} {
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 vec4(vertices[gl_VertexIndex], 0.0, 1.0);
} {
#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);
}}
builtin-programs/display/curve.folk wishes the GPU compiles function bboxBezier {{vec2 p0 vec2 p1 vec (
[ m23447:0 (s30980:0) ]
)builtin-programs/display/curve.folk wishes the GPU compiles function bboxBezier {{vec2 p0 vec2 p1 vec2 p2 vec2 p3} vec4 {
// Exact BBox to a quadratic bezier
// extremes
vec2 mi = min(p0,p3);
vec2 ma = max(p0,p3);
vec2 k0 = -1.0*p0 + 1.0*p1;
vec2 k1 = 1.0*p0 - 2.0*p1 + 1.0*p2;
vec2 k2 = -1.0*p0 + 3.0*p1 - 3.0*p2 + 1.0*p3;
vec2 h = k1*k1 - k0*k2;
if( h.x>0.0 )
{
h.x = sqrt(h.x);
//float t = (-k1.x - h.x)/k2.x;
float t = k0.x/(-k1.x-h.x);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.x + 3.0*s*s*t*p1.x + 3.0*s*t*t*p2.x + t*t*t*p3.x;
mi.x = min(mi.x,q);
ma.x = max(ma.x,q);
}
//t = (-k1.x + h.x)/k2.x;
t = k0.x/(-k1.x+h.x);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.x + 3.0*s*s*t*p1.x + 3.0*s*t*t*p2.x + t*t*t*p3.x;
mi.x = min(mi.x,q);
ma.x = max(ma.x,q);
}
}
if( h.y>0.0)
{
h.y = sqrt(h.y);
//float t = (-k1.y - h.y)/k2.y;
float t = k0.y/(-k1.y-h.y);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.y + 3.0*s*s*t*p1.y + 3.0*s*t*t*p2.y + t*t*t*p3.y;
mi.y = min(mi.y,q);
ma.y = max(ma.y,q);
}
//t = (-k1.y + h.y)/k2.y;
t = k0.y/(-k1.y+h.y);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.y + 3.0*s*s*t*p1.y + 3.0*s*t*t*p2.y + t*t*t*p3.y;
mi.y = min(mi.y,q);
ma.y = max(ma.y,q);
}
}
return vec4( mi, ma );
}}
builtin-programs/display/curve.folk wishes the GPU compiles function sdSegmentSq {{vec2 p vec2 a vec2 (
[ m23448:0 (s30983:0) ]
)builtin-programs/display/curve.folk wishes the GPU compiles function sdSegmentSq {{vec2 p vec2 a vec2 b} float {
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
vec2 d = pa - ba*h;
return dot(d, d);
}}
builtin-programs/display/curve.folk wishes the GPU compiles function udBezier {{vec2 p0 vec2 p1 vec2 (
[ m23449:0 (s30984:0) ]
)builtin-programs/display/curve.folk wishes the GPU compiles function udBezier {{vec2 p0 vec2 p1 vec2 p2 vec2 p3 vec2 pos} vec2 {
const int kNum = 50;
vec2 res = vec2(1e10,0.0);
vec2 a = p0;
for( int i=1; i<kNum; i++ )
{
float t = float(i)/float(kNum-1);
float s = 1.0-t;
vec2 b = p0*s*s*s + p1*3.0*s*s*t + p2*3.0*s*t*t + p3*t*t*t;
float d = sdSegmentSq( pos, a, b );
if( d<res.x ) res = vec2(d,t);
a = b;
}
return vec2(sqrt(res.x),res.y);
}}
builtin-programs/display/curve.folk wishes the GPU compiles pipeline curve {
{ vec2 p0 vec2 p1 vec2 (
[ m23547:0 (s37586:0) ]
)builtin-programs/display/curve.folk wishes the GPU compiles pipeline curve {
{ vec2 p0 vec2 p1 vec2 p2 vec2 p3 float thickness vec4 color} {
// Need to calculate the bounds of the curve
vec2 from = min(min(p0,p1),min(p2,p3));
vec2 to = max(max(p0,p1),max(p2,p3));
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.x, to.x) - thickness, max(from.y, to.y) + thickness),
max(from, to) + thickness
);
return vec4(vertices[gl_VertexIndex], 0.0, 1.0);
} {fn sdSegmentSq fn udBezier} {
vec2 p = gl_FragCoord.xy;
float px = 2.0; // sharpness
float t = thickness;
float be = udBezier( p0, p1, p2, p3, p ).x;
float d = be;
vec4 col = mix( vec4(0.0), color, 1.0-smoothstep(t, t + px*1.5, d) );
// control points
//d = length(p0-p); col = mix( col, vec4(1.0, 0., 0., 1.), 1.0-smoothstep(4,4+px,d) );
//d = length(p1-p); col = mix( col, vec4(0., 1.0, 0., 1.), 1.0-smoothstep(4,4+px,d) );
//d = length(p2-p); col = mix( col, vec4(0., 0., 1.0, 1.), 1.0-smoothstep(4,4+px,d) );
//d = length(p3-p); col = mix( col, vec4(1.0), 1.0-smoothstep(4,4+px,d) );
return col;
}
}
builtin-programs/image/image-lib.folk claims the image library is <C:cfileV8MUaU> (
[ m900:0 (s1396:0) ]
[ m899:0 (s1398:0) ]
[ m901:0 (s1399:0) ]
[ m902:0 (s1635:0) ]
[ m903:0 (s1431:0 s1432:0 s1798:0 s1801:0 s1803:0) ]
[ m905:0 (s1401:0) ]
[ m906:0 (s1402:0) ]
[ m907:0 (s1403:0) ]
[ m908:0 (s1404:0) ]
[ m910:0 (s1656:0) ]
[ m914:0 (s1771:0) ]
[ m934:0 (s2326:0 s2327:0 s2328:0 s2329:0 s2330:0) ]
[ m935:0 (s1732:0) ]
[ m937:0 (s1630:0) ]
[ m941:0 (s1638:0) ]
[ m1030:0 (s1809:0) ]
[ m1042:0 (s1823:0) ]
[ m2254:0 (s3345:0) ]
[ m2255:0 (s3350:0) ]
[ m2256:0 (s3351:0) ]
[ m13901:0 (s23863:0 s23866:0) ]
)builtin-programs/image/image-lib.folk claims the image library is <C:cfileV8MUaU>
builtin-programs/image/image-lib.folk claims the image uvx argtype definer is {apply \{fn\ envStack\ ()builtin-programs/image/image-lib.folk claims the image uvx argtype definer is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {uvx {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
} {builtin-programs/image/image-lib.folk 119}} {{this builtin-programs/image/image-lib.folk} {} {^defineImageArgtype {uvx {
set cc [C]
$cc extend $imageLib
$cc include <unistd.h>
$cc proc sockSendImage {int fd Image im} void {
// Image must be contiguous for now (TODO: copy if not)
FOLK_ENSURE(im.bytesPerRow == im.width * im.components);
uint32_t len;
len = sizeof(im.width);
write(fd, &len, 4); write(fd, &im.width, sizeof(im.width));
len = sizeof(im.height);
write(fd, &len, 4); write(fd, &im.height, sizeof(im.height));
len = sizeof(im.components);
write(fd, &len, 4); write(fd, &im.components, sizeof(im.components));
len = sizeof(im.bytesPerRow);
write(fd, &len, 4); write(fd, &im.bytesPerRow, sizeof(im.bytesPerRow));
size_t dataLen = (size_t)im.height * im.bytesPerRow;
len = (uint32_t)dataLen;
write(fd, &len, 4); write(fd, im.data, dataLen);
}
set lib [$cc compile]
$uvx argtype Image "$lib sockSendImage \$socket \$arg" {
import struct
from PIL import Image
# Receive image properties
width = struct.unpack('I', recv_frame(socket))[0]
height = struct.unpack('I', recv_frame(socket))[0]
components = struct.unpack('i', recv_frame(socket))[0]
bytesPerRow = struct.unpack('I', recv_frame(socket))[0]
# Receive image data
data = recv_frame(socket)
# Convert to PIL Image directly from buffer
if components == 1:
img = Image.frombuffer('L', (width, height), data, 'raw', 'L', bytesPerRow, 1)
elif components == 3:
img = Image.frombuffer('RGB', (width, height), data, 'raw', 'RGB', bytesPerRow, 1)
else:
raise ValueError(f"Unsupported number of components: {components}")
return img
}
} {builtin-programs/image/image-lib.folk 119}} imageLib <C:cfileV8MUaU> cc ::<reference.<C______>.00000000000000000002>}}}
builtin-programs/web/web.folk claims the websocket library is <C:cfilepPA9mK> ()builtin-programs/web/web.folk claims the websocket library is <C:cfilepPA9mK>
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd is (
[ m944:0 (s2130:0) ]
)builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd is a keyboard device
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd has ()builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:3:1.0-event-kbd has keymaps {}
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd is a (
[ m951:0 (s2249:0) ]
)builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd is a keyboard device
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd has k ()builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:3:1.0-event-kbd has keymaps {}
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd is a (
[ m952:0 (s2160:0) ]
)builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd is a keyboard device
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd has k ()builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usb-0:2:1.0-event-kbd has keymaps {}
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd is (
[ m911:0 (s1678:0) ]
)builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd is a keyboard device
builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd has ()builtin-programs/keyboard.folk claims /dev/input/by-path/pci-0000:03:00.3-usbv2-0:2:1.0-event-kbd has keymaps {}
sysmon.c claims folk-sva has self RAM usage 5810 MB ()sysmon.c claims folk-sva has self RAM usage 5810 MB
sysmon.c claims folk-sva has available RAM 4856 MB of 16156 MB ()sysmon.c claims folk-sva has available RAM 4856 MB of 16156 MB
builtin-programs/apriltags.folk claims libapriltag has been built with config {apply \{fn\ envStack\ (
[ m915:0 (s2238:0 s2239:0 s2240:0 s2250:0 s2251:0 s2253:0 s2256:0 s2259:0) ]
[ m936:0 (s1629:0) ]
[ m943:0 (s6885:0) ]
[ m953:0 (s6279:0) ]
[ m954:0 (s2108:0) ]
)builtin-programs/apriltags.folk claims libapriltag has been built with config {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}
builtin-programs/apriltags.folk claims the AprilTag detector maker is {apply \{fn\ envStack\ args\}\ (
[ m23568:0 (s31212:0) ]
)builtin-programs/apriltags.folk claims the AprilTag detector maker is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} ^makeAprilTagDetector {{TAG_FAMILY QUAD_DECIMATE NTHREADS} {
set cc [C]
$cc extend $imageLib
configCcWithLibapriltag $cc
$cc include <apriltag.h>
$cc include <$TAG_FAMILY.h>
$cc include <math.h>
$cc code {
static apriltag_detector_t *td;
static apriltag_family_t *tf;
}
$cc proc detectInit {} void {
td = apriltag_detector_create();
tf = ${TAG_FAMILY}_create();
apriltag_detector_add_family_bits(td, tf, 3);
td->quad_decimate = ${QUAD_DECIMATE};
td->nthreads = ${NTHREADS};
}
$cc proc detect {Image gray} Jim_Obj* {
FOLK_ENSURE(gray.components == 1 || gray.components == 3);
uint8_t* grayBuf = gray.data;
if (gray.components == 3) {
grayBuf = malloc(gray.width * gray.height);
for (uint32_t i = 0; i < gray.width * gray.height; i++) {
uint8_t r = gray.data[i*3], g = gray.data[i*3+1], b = gray.data[i*3+2];
grayBuf[i] = (uint8_t)(0.299f*r + 0.587f*g + 0.114f*b + 0.5f);
}
}
image_u8_t im = (image_u8_t) { .width = gray.width, .height = gray.height, .stride = gray.components == 3 ? gray.width : gray.bytesPerRow, .buf = grayBuf };
zarray_t *detections = apriltag_detector_detect(td, &im);
int detectionCount = zarray_size(detections);
Jim_Obj* detectionObjs[detectionCount];
for (int i = 0; i < detectionCount; i++) {
apriltag_detection_t *det;
zarray_get(detections, i, &det);
int size = sqrt((det->p[0][0] - det->p[1][0])*(det->p[0][0] - det->p[1][0]) + (det->p[0][1] - det->p[1][1])*(det->p[0][1] - det->p[1][1]));
double angle = atan2(-1 * (det->p[1][1] - det->p[0][1]), det->p[1][0] - det->p[0][0]);
detectionObjs[i] = Jim_ObjPrintf("id %d c {%f %f} p {{%f %f} {%f %f} {%f %f} {%f %f}} size %d angle %f",
det->id,
det->c[0], det->c[1],
det->p[0][0], det->p[0][1],
det->p[1][0], det->p[1][1],
det->p[2][0], det->p[2][1],
det->p[3][0], det->p[3][1],
size, angle);
}
zarray_destroy(detections);
if (gray.components == 3) free(grayBuf);
Jim_Obj* result = Jim_NewListObj(interp, detectionObjs, detectionCount);
return result;
}
$cc proc detectCleanup {} void {
${TAG_FAMILY}_destroy(tf);
apriltag_detector_destroy(td);
}
set detector [$cc compile]
$detector detectInit
return $detector
} {builtin-programs/apriltags.folk 50}}}}}
builtin-programs/saving/save-holds.folk claims saving is ready (
[ m918:0 (s1563:0) ]
)builtin-programs/saving/save-holds.folk claims saving is ready
builtin-programs/saving/save-holds.folk claims the saved holds are loaded ()builtin-programs/saving/save-holds.folk claims the saved holds are loaded
builtin-programs/saving/migrate.folk claims the migration is complete (
[ m919:0 (s1564:0 s1565:0) ]
)builtin-programs/saving/migrate.folk claims the migration is complete
the next program id is 83 ()the next program id is 83
builtin-programs/editor/editor.folk claims editor buffer for 63 is {When $this has camera slice /slic ()builtin-programs/editor/editor.folk claims editor buffer for 63 is {When $this has camera slice /slice/ {
Wish $this displays camera slice $slice
}
}
builtin-programs/editor/editor.folk claims editor buffer for 54 is set\ COLS\ 3\nWish\ tag\ \$this\ i ()builtin-programs/editor/editor.folk claims editor buffer for 54 is set\ COLS\ 3\nWish\ tag\ \$this\ is\ stabilized\nWish\ \$this\ is\ outlined\ green\nWish\ \$this-display\ has\ a\ canvas\ with\ settle\ 0ms\ width\ 1024\ height\ 1024\nWhen\ display\ /disp/\ has\ width\ /displayWidth/\ height\ /displayHeight/\ &\\\n\ \ \ \ \ display\ /disp/\ has\ intrinsics\ /displayIntrinsics/\ &\\\n\ \ \ \ \ the\ pose\ library\ is\ /poseLib/\ &\\\n\ \ \ \ \ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \ the\ quad\ changer\ is\ /quadChange/\ &\\\n\ \ \ \ \ \$this\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ fn\ quadChange\n\n\ \ \ \ set\ frameGeom\ \[list\ width\ \[*\ \$geom(width)\ 0.5\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height\ \[*\ \$geom(height)\ 0.5\]\]\n\ \ \ \ Claim\ \$this-display\ has\ resolved\ geometry\ \$frameGeom\n\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ resolved\ geometry\ \$frameGeom\n\ \ \ \ \ \ \ \ When\ /someone/\ wishes\ \$this-frame-\$i\ is\ outlined\ /color/\ &\\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \$this-frame-\$i\ has\ quad\ /frameQuad/\ \{\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispQuad\ \[quadChange\ \$frameQuad\ \"display\ \$disp\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ dispPoints\ \[lmap\ v\ \[\$quadLib\ vertices\ \$dispQuad\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$poseLib\ project\ \$displayIntrinsics\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$displayWidth\ \$displayHeight\ \$v\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ dispPoints\ \[lindex\ \$dispPoints\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ draw\ a\ line\ onto\ \$disp\ with\ points\ \$dispPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width\ 4\ color\ \$color\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\ \$this\ has\ quad\ /q/\ \{\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ scale\ \$q\ 50%\]\n\ \ \ \ set\ displayQuad\ \[\$quadLib\ move\ \$displayQuad\ up\ 60%\ right\ 160%\]\n\ \ \ \ Claim\ -keep\ 10ms\ \$this-display\ has\ quad\ \$displayQuad\n\ \ \ \ Wish\ -keep\ 10ms\ \$this-display\ is\ outlined\ white\n\}\nWhen\ the\ quad\ library\ is\ /quadLib/\ &\\\n\ \ \ \ \$this\ has\ quad\ /q/\ &\\\n\ \ \ \ \$this-display\ has\ resolved\ geometry\ /geom/\ &\\\n\ \ \ \ the\ animation\ toy's\ fps\ is\ /FPS/\ &\\\n\ \ \ \ the\ animation\ toy's\ frame\ count\ is\ /N_FRAMES/\ \{\n\n\ \ \ \ Wish\ -keep\ 10ms\ \$this\ is\ labelled\ \"FPS:\ \$FPS\nFrame\ count:\ \$N_FRAMES\"\n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <=\ \$N_FRAMES\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ col\ \[expr\ \{(\$i\ -\ 1)\ %\ \$COLS\}\]\n\ \ \ \ \ \ \ \ set\ row\ \[expr\ \{(\$i\ -\ 1)\ /\ \$COLS\}\]\n\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ scale\ \$q\ 30%\]\n\ \ \ \ \ \ \ \ set\ frameQuad\ \[\$quadLib\ move\ \$frameQuad\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ 240%\ down\ 300%\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ right\ \$\{col\}00%\ down\ \$\{row\}00%\]\n\ \ \ \ \ \ \ \ Claim\ \$this-frame-\$i\ has\ quad\ \$frameQuad\n\n\ \ \ \ \ \ \ \ When\ -nonatomically\ \$this-frame-\$i\ has\ camera\ slice\ /slice/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ When\ -nonatomically\ the\ clock\ time\ is\ /t/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Hold!\ -key\ anim\ -keep\ 25ms\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{round(\$t\ *\ \$FPS)\ %\ \$N_FRAMES\ ==\ (\$i\ -\ 1)\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ green\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-display\ displays\ image\ \$slice\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ with\ width\ \$geom(width)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ \$this-frame-\$i\ is\ outlined\ red\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n
builtin-programs/editor/editor.folk claims editor buffer for 69 is {Wish $this is outlined purple
Wis ()builtin-programs/editor/editor.folk claims editor buffer for 69 is {Wish $this is outlined purple
Wish $this is titled "piano"
Wish to play audio "/home/folk/sounds/lo-fi-jazz-piano.wav"
}
builtin-programs/editor/editor.folk claims editor buffer for 11 is {Wish $this displays image "https: ()builtin-programs/editor/editor.folk claims editor buffer for 11 is {Wish $this displays image "https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif"
}
builtin-programs/editor/editor.folk claims editor buffer for 82 is When\ \$this\ has\ canvas\ /id/\ w ()builtin-programs/editor/editor.folk claims editor buffer for 82 is When\ \$this\ has\ canvas\ /id/\ with\ /...wiOptions/\ &\\\n\ \ \ \ \ \$this\ has\ canvas\ projection\ /surfaceToClip/\ &\\\n\ \ \ \ \ /p/\ is\ a\ viewport\ \{\n\n\ \ \ \ set\ wiResolution\ \[list\ \[dict\ get\ \$wiOptions\ width\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$wiOptions\ height\]\]\n\ \ \ \ Wish\ \$p\ has\ contours\ with\ \\\n\ \ \ \ \ \ threshold\ 28\ epsilon\ 3.0\ minLength\ 0.01\n\n\ \ \ \ set\ scale\ 0.5\n\ \ \ \ set\ palette\ \{\{1\ 0\ 0\ 1\}\ \{0\ 1\ 0\ 1\}\ \{0\ 0\ 1\ 1\}\ \{1\ 1\ 0\ 1\}\n\ \ \ \ \ \ \ \ \{1\ 0\ 1\ 1\}\ \{0\ 1\ 1\ 1\}\ \{1\ 0.5\ 0\ 1\}\ \{1\ 1\ 1\ 1\}\}\n\ \ \ \ When\ \$p\ has\ contours\ /cs/\ with\ /...any/\ \{\n\ \ \ \ \ \ \ \ Wish\ \$this\ is\ labelled\ \[llength\ \$cs\]\n\ \ \ \ \ \ \ \ set\ instances\ \[list\]\n\ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ \[llength\ \$cs\]\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ contour\ \[lindex\ \$cs\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ color\ \[lindex\ \$palette\ \$(\$j\ %\ \[llength\ \$palette\])\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[lindex\ \$contour\ 0\]\ sx\ sy\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$contour\]\ -\ 1\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ from\ \[::vec2::scale\ \[lindex\ \$contour\ \$i\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ to\ \[::vec2::scale\ \[lindex\ \$contour\ \[+\ \$i\ 1\]\]\ \$scale\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ instances\ \[list\ \$wiResolution\ \$surfaceToClip\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$from\ \$to\ 0.001\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$color\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ Wish\ the\ GPU\ draws\ pipeline\ \"line\"\ onto\ canvas\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ with\ instances\ \$instances\n\ \ \ \ \}\n\ \ \ \ Wish\ \$this\ is\ outlined\ red\n\}\n
builtin-programs/editor/editor.folk claims editor buffer for 83 is {Claim $this is a viewport
Wish $t ()builtin-programs/editor/editor.folk claims editor buffer for 83 is {Claim $this is a viewport
Wish $this is outlined white}
builtin-programs/editor/editor.folk claims editor buffer for 67 is {Wish $this is outlined magenta
Wi ()builtin-programs/editor/editor.folk claims editor buffer for 67 is {Wish $this is outlined magenta
Wish $this is titled "laser"
Wish to play audio "/home/folk/sounds/laser-shot.wav"
}
builtin-programs/editor/editor.folk claims editor {49 editor} on program 63 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 63 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {49 editor} on program {49 editor} has font options ()builtin-programs/editor/editor.folk claims editor {49 editor} on program {49 editor} has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {49 editor} on program 54 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 54 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {49 editor} on program 11 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 11 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {49 editor} on program 82 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 82 has font options with scale 0.003
builtin-programs/editor/editor.folk claims editor {49 editor} on program 83 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 83 has font options with scale 0.003
builtin-programs/editor/editor.folk claims editor {49 editor} on program 12 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 12 has font options with scale 0.00751314800902
builtin-programs/editor/editor.folk claims editor {49 editor} on program 67 has font options with sca ()builtin-programs/editor/editor.folk claims editor {49 editor} on program 67 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {50 editor} on program 54 has font options with sca ()builtin-programs/editor/editor.folk claims editor {50 editor} on program 54 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {50 editor} on program 12 has font options with sca ()builtin-programs/editor/editor.folk claims editor {50 editor} on program 12 has font options with scale 0.01
builtin-programs/editor/editor.folk claims editor {50 editor} on program 69 has font options with sca ()builtin-programs/editor/editor.folk claims editor {50 editor} on program 69 has font options with scale 0.01
builtin-programs/calibrate/calibration-board.folk claims the calibrated print scale is 1.07367149758 ()builtin-programs/calibrate/calibration-board.folk claims the calibrated print scale is 1.07367149758
builtin-programs/calibrate/calibration-board.folk claims the calibrated print translation is {-15 -24 ()builtin-programs/calibrate/calibration-board.folk claims the calibrated print translation is {-15 -24}
builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPs is {apply \{fn\ e ()builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPs is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}} {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}
builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPdf is {apply \{fn\ ()builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPdf is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}
builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPng is {apply \{fn\ ()builtin-programs/calibrate/calibration-board.folk claims the makeCalibrationBoardPng is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPng {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}
builtin-programs/calibrate/calibration-board.folk wishes the web server handles route /calibrate/boar (
[ m4493:0 () ]
)builtin-programs/calibrate/calibration-board.folk wishes the web server handles route /calibrate/board.pdf with hidden true handler {applyBlock \n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPdf\]\n {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPng {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}
builtin-programs/calibrate/calibration-board.folk wishes the web server handles route /calibrate/boar (
[ m4494:0 () ]
)builtin-programs/calibrate/calibration-board.folk wishes the web server handles route /calibrate/board.png with hidden true handler {applyBlock \n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/png\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \[makeCalibrationBoardPng\]\n {{this builtin-programs/calibrate/calibration-board.folk} {} {marginLeft 48 measureTop 24 marginTop 48 measureLeft 24 tagInnerSideLength 70} {printLib <C:cfileDzXJHE>} {} {modelLib <library:/tmp/modelLib_OwSqeI.tcl>} {} {matLib <C:cfile5JsRBY>} {^makeCalibrationBoardPdf {{} {
set ps [makeCalibrationBoardPs]
set fp [open [list |ps2pdf - - <<$ps] rb]
set pdf [read $fp]; close $fp
return $pdf
} {builtin-programs/calibrate/calibration-board.folk 206}} ^makeCalibrationBoardPng {{} \n\ \ \ \ set\ ps\ \[makeCalibrationBoardPs\]\n\ \ \ \ set\ psFile\ \[file\ tempfile\].ps\n\ \ \ \ set\ fp\ \[open\ \$psFile\ w\]\;\ puts\ \$fp\ \$ps\;\ close\ \$fp\n\ \ \ \ set\ pngFile\ \[file\ tempfile\].png\n\ \ \ \ exec\ gs\ -dNOPAUSE\ -dBATCH\ -sFONTPATH=vendor/fonts\ \\\n\ \ \ \ \ \ \ \ -sDEVICE=png16m\ -r144\ \\\n\ \ \ \ \ \ \ \ -sOutputFile=\$pngFile\ \$psFile\n\ \ \ \ set\ fp\ \[open\ \$pngFile\ rb\]\n\ \ \ \ set\ png\ \[read\ \$fp\]\;\ close\ \$fp\n\ \ \ \ return\ \$png\n {builtin-programs/calibrate/calibration-board.folk 214}} ^makeCalibrationBoardPs {{} \n\ \ \ \ set\ model\ \[\$modelLib\ unitModel\]\n\n\ \ \ \ package\ require\ linalg\n\ \ \ \ namespace\ import\ ::math::linearalgebra::add\n\n\ \ \ \ Expect!\ the\ paper\ formats\ are\ /formats/\n\ \ \ \ set\ formatName\ \[QueryOne!\ paper\ format\ /./\ is\ the\ default\ paper\ format\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ -default\ letter\]\n\ \ \ \ lassign\ \[dict\ get\ \$formats(\$formatName)\ pageSize\]\ PageWidth\ PageHeight\n\n\ \ \ \ set\ innerToOuter\ 0.333333\n\n\ \ \ \ set\ tagOuterLengthPs\ \[expr\ \{\$tagInnerSideLength\ *\ 10/6\}\]\n\n\ \ \ \ set\ H_modelToPs\ \[\$matLib\ estimateHomography\ \[subst\ \{\n\ \ \ \ \ \ \ \ \{1\ 1\ \$tagInnerSideLength\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{1\ 0\ \$tagInnerSideLength\ 0\}\n\ \ \ \ \ \ \ \ \{0\ 1\ 0\ \$tagInnerSideLength\}\n\ \ \ \ \ \ \ \ \{0\ 0\ 0\ 0\}\n\ \ \ \ \}\]\]\n\n\ \ \ \ set\ ps\ \[subst\ \{\n\ \ \ \ \ \ \ \ %!PS\n\ \ \ \ \ \ \ \ <<\ /PageSize\ \\\[\$PageWidth\ \$PageHeight\\\]\ >>\ setpagedevice\n\n\ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$PageHeight\ \[/\ \$marginTop\ 2\]\]\ translate\n\ \ \ \ \ \ \ \ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ (Folk\ calibration\ board)\ show\n\ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ 1\ setlinecap\n\ \ \ \ \ \ \ \ 2\ setlinewidth\ 0.67\ 0.1\ 0.1\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ top\ measure,\ with\ arrow\ up\ to\ top\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \[-\ \$PageHeight\ \$measureTop\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[-\ \$PageHeight\ \$measureTop\]\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \[expr\ \{\$PageHeight\ -\ 2\}\]\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ \[expr\ \{\$PageHeight\ -\ 8\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$PageHeight\ -\ \$measureTop/2\ -\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ top\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ Short\ red\ segment\ at\ bottom\ measure,\ with\ arrow\ down\ to\ bottom\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 20\}\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 20\}\]\ \$measureTop\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ \$measureTop\ moveto\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ -\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \[/\ \$PageWidth\ 2\]\ 2\ moveto\n\ \ \ \ \ \ \ \ \[expr\ \{\$PageWidth/2\ +\ 4\}\]\ 8\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[expr\ \{\$PageWidth/2\ +\ 12\}\]\ \[expr\ \{\$measureTop/2-\ 3\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to\ bottom\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ 0.1\ 0.1\ 0.67\ setrgbcolor\n\n\ \ \ \ \ \ \ \ %\ Short\ blue\ segment\ at\ left\ measure,\ with\ arrow\ left\ to\ left\ edge.\n\ \ \ \ \ \ \ \ 2\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ -\ 20\}\]\ moveto\n\ \ \ \ \ \ \ \ \$measureLeft\ \[expr\ \{\$PageHeight/2\ +\ 20\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ 1\ setlinewidth\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ \$measureLeft\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ -\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\n\ \ \ \ \ \ \ \ 2\ \[/\ \$PageHeight\ 2\]\ moveto\n\ \ \ \ \ \ \ \ 8\ \[expr\ \{\$PageHeight/2\ +\ 4\}\]\ lineto\n\ \ \ \ \ \ \ \ stroke\n\ \ \ \ \ \ \ \ newpath\ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 30\}\]\ moveto\n\ \ \ \ \ \ \ \ (Measure\ to)\ show\n\ \ \ \ \ \ \ \ \[/\ \$measureLeft\ 4\]\ \[expr\ \{\$PageHeight/2\ -\ 37\}\]\ moveto\n\ \ \ \ \ \ \ \ (left\ edge\ of\ paper)\ show\n\n\ \ \ \ \ \ \ \ %\ We\ should\ flip\ the\ coordinate\ system\ to\ match\ the\ model\ coordinate\ system,\n\ \ \ \ \ \ \ \ %\ so\ (0,\ 0)\ is\ top-left.\n\ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \$marginLeft\ \[-\ \$marginTop\ \$PageHeight\]\ translate\ \ \ \ \ \ \ \ \n\n\ \ \ \ \ \ \ \ \[set\ tagIdx\ -1\]\n\ \ \ \ \ \ \ \ \[join\ \[lmap\ \{id\ modelTag\}\ \$model\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isPrintedTag\ \$id\]\}\ \{\ continue\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ tagIdx\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelInnerTopLeft\ \[lindex\ \[dict\ get\ \$modelTag\ p\]\ 3\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ modelOuterTopLeft\ \[add\ \$modelInnerTopLeft\ \[list\ -\$innerToOuter\ -\$innerToOuter\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \[\$matLib\ applyHomography\ \$H_modelToPs\ \$modelOuterTopLeft\]\ psX\ psY\n\ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$psX\ \[+\ \$psY\ \$tagOuterLengthPs\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$tagOuterLengthPs\ -\$tagOuterLengthPs\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[\$printLib\ tagPsForId\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 0\ setgray\ /Helvetica\ findfont\ 14\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ 1\ 0\ 0\ setrgbcolor\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ newpath\ \$psX\ \$psY\ moveto\ 1\ -1\ scale\ (\$tagIdx)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ grestore\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ %\ Label\ the\ inner\ side\ length:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[if\ \{\$tagIdx\ ==\ 1\}\ \{\ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gsave\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psX\ +\ (\$tagOuterLengthPs\ -\ \$tagInnerSideLength)/2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$psY\ -\ 15\}\]\ translate\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1\ -1\ scale\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0.1\ 0.67\ 0.1\ setrgbcolor\ 2\ setlinewidth\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ \$tagInnerSideLength\ 0\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 0\ moveto\ 0\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ \$tagInnerSideLength\ 0\ moveto\ \$tagInnerSideLength\ -5\ lineto\ stroke\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /Helvetica\ findfont\ 7\ scalefont\ setfont\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ newpath\ 0\ 5\ moveto\ (inner\ side\ length)\ show\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ grestore\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\n\ \ \ \ \ \ \ \ showpage\n\ \ \ \ \}\]\n\n\ \ \ \ return\ \$ps\n {builtin-programs/calibrate/calibration-board.folk 50}}}}}
builtin-programs/recognition/contours.folk claims the contour library is <C:cfileQnzeGL> (
[ m940:0 (s1636:0) ]
)builtin-programs/recognition/contours.folk claims the contour library is <C:cfileQnzeGL>
builtin-programs/recognition/contours.folk wishes 83 has camera slice (
[ m47767:1064 (s64520:1262) ]
)builtin-programs/recognition/contours.folk wishes 83 has camera slice
builtin-programs/image/gif-lib.folk claims the gif library is <C:cfiled3kiwc> (
[ m945:0 (s1657:0) ]
[ m946:0 (s1658:0) ]
)builtin-programs/image/gif-lib.folk claims the gif library is <C:cfiled3kiwc>
builtin-programs/image/png-lib.folk claims the png library is <C:cfileimXyHY> (
[ m966:0 (s1733:0) ]
)builtin-programs/image/png-lib.folk claims the png library is <C:cfileimXyHY>
builtin-programs/image/jpeg-lib.folk claims the jpeg library is <C:cfileZXB3iE> (
[ m1000:0 (s1772:0) ]
[ m1002:0 (s2398:0 s2399:0) ]
[ m1006:0 (s1777:0) ]
[ m1008:0 (s1779:0) ]
[ m23569:0 (s31213:0) ]
)builtin-programs/image/jpeg-lib.folk claims the jpeg library is <C:cfileZXB3iE>
builtin-programs/web/apriltag-frame.folk wishes the web server handles route /apriltag-frame with han (
[ m1007:0 () ]
)builtin-programs/web/apriltag-frame.folk wishes the web server handles route /apriltag-frame with handler {applyBlock \n\ \ \ \ \ \ \ \ set\ frames\ \[Query!\ camera\ /cam/\ has\ frame\ /im/\ at\ timestamp\ /ts/\]\n\ \ \ \ \ \ \ \ set\ frame\ \[lindex\ \$frames\ end\]\n\ \ \ \ \ \ \ \ dict\ with\ frame\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$__ref\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ filename\ \"/tmp/web-image-frame.jpg\"\n\ \ \ \ \ \ \ \ \ \ \ \ \$jpegLib\ saveAsJpeg\ \$im\ \$filename\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ \ \ \ \ \ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ \ \ \ \ \ \ \ \ set\ imageData\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ \ \ \ \ \ \ \ \ close\ \$fd\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ tags\ \[Query!\ tag\ /id/\ has\ detection\ /det/\ on\ camera\ \$cam\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ at\ timestamp\ \$ts\]\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"Tags:\ \$tags\"\n\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$__ref\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ package\ require\ base64\n\ \ \ \ \ \ \ \ html\ \[subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ src=\"data:image/png\;base64,\[binary\ encode\ base64\ \$imageData\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:absolute\;top:0\;left:0\">\n\ \ \ \ \ \ \ \ \ \ \ \ <svg\ width=\"100%\"\ height=\"100%\"\ style=\"position:absolute\;top:0\;left:0\;pointer-events:none\;\">\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$tags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ det\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ det\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ </svg>\n\ \ \ \ \ \ \ \ \ \ \ \ </body>\n\ \ \ \ \ \ \ \ \ \ \ \ </html>\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {{this builtin-programs/web/apriltag-frame.folk} {} {} {jpegLib <C:cfileZXB3iE>} {}}}
builtin-programs/web/camera-frame.folk wishes the web server handles route /camera-frame with handler (
[ m1009:0 () ]
)builtin-programs/web/camera-frame.folk wishes the web server handles route /camera-frame with handler {applyBlock \n\ \ \ \ \ \ \ \ set\ camera\ \[dict\ getdef\ \$QUERY\ camera\ /any/\]\n\ \ \ \ \ \ \ \ ForEach!\ camera\ \$camera\ has\ jpeg\ frame\ /jpeg/\ at\ timestamp\ /any/\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ data\ \[\$jpegLib\ jpegData\ \$jpeg\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ fsize\ \[string\ bytelength\ \$data\]\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ data\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"camera-frame:\ No\ valid\ camera\ frame\ found\ (for\ \$camera)\"\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\\n\\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \$data\n\ \ \ \ {{this builtin-programs/web/camera-frame.folk} {} {} {jpegLib <C:cfileZXB3iE>} {}}}
builtin-programs/calibrate/calibrate-page.folk wishes the web server handles route /calibrate with hi (
[ m1051:0 () ]
)builtin-programs/calibrate/calibrate-page.folk wishes the web server handles route /calibrate with hidden true handler {applyBlock \n\ \ \ \ package\ require\ base64\n\n\ \ \ \ set\ camera\ \$QUERY(camera)\n\ \ \ \ set\ display\ \$QUERY(display)\n\n\ \ \ \ #\ Query\ the\ camera\ resolution\ for\ proper\ aspect\ ratio\ in\ preview\ (defaults\ to\ 1920x1080)\n\ \ \ \ Expect!\ camera\ \$camera\ has\ width\ /cameraWidth/\ height\ /cameraHeight/\n\n\ \ \ \ upvar\ ^html\ ^html\n\ \ \ \ html\ \[csubst\ \{\n\ \ \ \ \ \ <html>\n\ \ \ \ \ \ \ \ <head>\n\ \ \ \ \ \ \ \ \ \ <title>Folk:\ Calibrate</title>\n\ \ \ \ \ \ \ \ \ \ <style>\n\ \ \ \ \ \ \ \ \ \ \ body\ \{\ margin:\ 0\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ article\ \{\ max-width:\ 600px\;\ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\ top:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ min(calc(100vw\ -\ 650px),\ 550px)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 100vh\;\ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ padding:\ 1em\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ box-sizing:\ border-box\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ right\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\;\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ @media\ (max-width:\ 800px)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ text-align:\ left\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ aside\ iframe\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 65%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ height:\ calc(65cqw\ *\ \$cameraHeight\ /\ \$cameraWidth\ +\ 72px)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ article\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ position:\ fixed\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ 0\;\ right:\ 0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ max-height:\ 50vh\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ max-width:\ 100%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ overflow-y:\ auto\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ </style>\n\ \ \ \ \ \ \ \ </head>\n\ \ \ \ \ \ <body>\n\ \ \ \ \ \ \ \ <span\ id=\"status\">Status</span>\n\ \ \ \ \ \ \ \ <script\ src=\"/lib/folk.js\"></script>\n\ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ function\ uuidv4()\ \{\n\ \ \ \ \ \ \ \ \ \ \ return\ (\[1e7\]+-1e3+-4e3+-8e3+-1e11).replace(/\[018\]/g,\ c\ =>\n\ \ \ \ \ \ \ \ \ \ \ \ \ (c\ ^\ crypto.getRandomValues(new\ Uint8Array(1))\[0\]\ &\ 15\ >>\ c\ /\ 4).toString(16)\n\ \ \ \ \ \ \ \ \ \ \ )\;\n\ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ const\ self\ =\ uuidv4()\;\n\n\ \ \ \ \ \ \ \ \ const\ folk\ =\ new\ FolkWS(document.getElementById('status'))\;\n\ \ \ \ \ \ \ \ \ folk.send(`\n\ \ \ \ On\ unmatch\ \{\n\ \ \ \ \ \ \ \ Hold!\ -on\ builtin-programs/calibrate/calibrate.folk\ -key\ \{start\ calibration\}\ \{\}\n\ \ \ \ \}\n\ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ <aside\ style=\"container-type:\ inline-size\">\n\ \ \ \ \ \ \ \ \ \ <p>Use\ this\ camera\ preview\ to\ debug\ why\ printed\ and/or\ projected\ tags\ aren't\ being\ recognized\ (maybe\ overexposure,\ maybe\ your\ camera\ isn't\ in\ a\ good\ position):</p>\n\ \ \ \ \ \ \ \ \ \ <div\ style=\"position:\ relative\">\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ src=\"/camera?camera=\$\[string\ map\ \{/\ %2F\}\ \$camera\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"border:\ 1px\ solid\ #999\"></iframe>\n\ \ \ \ \ \ \ \ \ \ \ \ \$\[HtmlWhen\ /someone/\ detects\ calibration\ tags\ /detectedTags/\ on\ camera\ \$camera\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ concat\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[subst\ \{<svg\ class=\"apriltag-overlay\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ viewBox=\"0\ 0\ \$cameraWidth\ \$cameraHeight\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ style=\"position:\ absolute\;\ top:\ 1px\;\ left:\ 1px\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ width:\ 100%\;\ height:\ calc(100cqw\ *\ \$cameraHeight\ /\ \$cameraWidth)%\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pointer-events:\ none\;\">\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[join\ \[lmap\ tag\ \$detectedTags\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ coords\ \[lmap\ point\ \$points\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ \"%g,%g\"\ \[lindex\ \$point\ 0\]\ \[lindex\ \$point\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ coords\ \[lindex\ \$coords\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ id\ \[dict\ get\ \$tag\ id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subst\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <polyline\ points=\"\$coords\"\ fill=\"none\"\ stroke=\"green\"\ stroke-width=\"3\"\ />\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ <text\ x=\"\[lindex\ \$points\ 0\ 0\]\"\ y=\"\[lindex\ \$points\ 0\ 1\]\"\ fill=\"green\"\ font-size=\"12\">\$\{id\}</text>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\ \"\\n\"\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"</svg>\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ </div>\n\ \ \ \ \ \ \ \ </aside>\n\n\ \ \ \ \ \ \ \ <article>\n\ \ \ \ \ \ \ \ <ol>\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Print\ the\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>We're\ going\ to\ print\ this\ calibration\ board\ and\ glue/tape\ it\ to\n\ \ \ \ \ \ \ \ \ \ \ \ something\ solid\ and\ flat\ (hardcover\ book,\ solid\ cardboard,\n\ \ \ \ \ \ \ \ \ \ \ \ etc):</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <img\ width=\"200\"\ src=\"/calibrate/board.png\"\ style=\"border:\ 1px\ solid\ gray\">\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Make\ sure\ <a\ href=\"https://github.com/FolkComputer/folk#printer-support\">your\ printer\ is\ set\ up</a>\ for\ Folk\ to\ print.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Print\ the\ calibration\ board\ through\ Folk:\ <button\ id=\"boardPrintThroughFolk\">Print\ Calibration\ Board\ through\ Folk</button>\ (print\ through\ Folk\ so\ that\ we\ can\ calibrate\ the\ way\ you\ will\ actually\ print)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ boardPrintThroughFolk.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ makeCalibrationBoardPdf\ is\ /maker/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdf\ \[\{*\}\\\$maker\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ boardPdfFile\ \[file\ tempfile\ /tmp/folk-calibration-board-XXXXXX\].pdf\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ fd\ \[open\ \\\$boardPdfFile\ wb\]\;\ puts\ \\\$fd\ \\\$boardPdf\;\ close\ \\\$fd\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Notify:\ print\ pdf\ \\\$boardPdfFile\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Try\ to\ keep\ the\ board\ from\ bending\ or\ warping.\ Printing\ on\ cardstock\ can\ help.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Measure\ your\ calibration\ board.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>On\ your\ calibration\ board,\ measure\ each\ indicator\ in\ millimeters\ and\ enter\ it\ here.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ (Try\ to\ be\ as\ accurate\ as\ possible,\ like\ to\ within\ half\ a\ millimeter\ or\ better\ --\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ more\ accurate,\ the\ better\ your\ calibration\ will\ be.)</p>\n\ \ \ \ \ \ \ \ \ \ \ \ <ul>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 67%\ 10%)\">Tag\ inner\ side\ length:\ <input\ id=\"boardTagSideLengthMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 67%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(10%\ 10%\ 67%)\">Left\ margin:\ <input\ id=\"boardLeftMm\"\ type=\"text\"\ style=\"background:\ rgb(10%\ 10%\ 67%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Top\ margin:\ <input\ id=\"boardTopMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <li\ style=\"color:\ rgb(67%\ 10%\ 10%)\">Bottom\ margin:\ <input\ id=\"boardBottomMm\"\ type=\"text\"\ style=\"background:\ rgb(67%\ 10%\ 10%\ /\ 15%)\">mm</li>\n\ \ \ \ \ \ \ \ \ \ \ \ </ul>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Run\ the\ calibration\ process.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Start\ calibration:\ <button\ id=\"startCalibration\">Start\ Calibration</button></p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ startCalibration.addEventListener('click',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (!(\[boardTagSideLengthMm.value,\ boardLeftMm.value,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boardTopMm.value,\ boardBottomMm.value\].every(x\ =>\ x\ !=\ \"\"\ &&\ !isNaN(x))))\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ alert(\"Error:\ You\ need\ to\ type\ in\ valid\ measurements\ before\ clicking\ Start\ Calibration.\")\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ measurements\ =\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tagSideLength:\ boardTagSideLengthMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ left:\ boardLeftMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ top:\ boardTopMm.value\ +\ 'mm',\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ bottom:\ boardBottomMm.value\ +\ 'mm'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\;\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold('start\ calibration',\ tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Wish\ to\ calibrate\ camera\ \"\$camera\"\ to\ display\ \"\$display\"\ using\ measurements\ \\\$\{measurements\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>Are\ the\ projected\ tags\ too\ big\ to\ fit\ in\ the\ gaps\ between\ printed\ tags?</strong>\ Adjust\ this\ slider\ to\ reset\ &\ adjust\ the\ default\ projected\ tag\ size:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"100\"\ value=\"100\"\ class=\"slider\"\ id=\"projected-tag-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('projected-tag-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ scale\ =\ e.target.value\ /\ 100.0\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.run(tcl`\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Expect!\ the\ calibration\ HoldDefaultModel!\ is\ /HoldDefaultModel!/\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[set\ HoldDefaultModel!\]\ \\\$\{scale\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Adjust\ this\ slider\ to\ choose\ how\ many\ calibration\ poses\ you\ want\ to\ record:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <input\ type=\"range\"\ min=\"10\"\ max=\"25\"\ value=\"10\"\ class=\"slider\"\ id=\"calibration-poses-max-slider\">\n\ \ \ \ \ \ \ \ \ \ \ \ </p>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ document.getElementById('calibration-poses-max-slider').addEventListener('input',\ (e)\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationPosesMax\ =\ parseInt(e.target.value)\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.hold(`calibration\ poses\ max`,\ tcl`\nClaim\ the\ calibration\ poses\ max\ is\ \\\$\{calibrationPosesMax\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ `,\ 'builtin-programs/calibrate/calibrate.folk')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Once\ you\ start\ calibration,\ you'll\ see\ some\ AprilTags\ get\ automatically\ projected\ on\ your\ table.\ Move\ your\ board\ to\ the\ projected\ tags\ <em>so\ that\ at\ least\ one\ projected\ tag\ sits\ inside\ the\ gap\ between\ printed\ AprilTags</em>,\ wait\ a\ second\ for\ the\ projected\ tags\ to\ refit\ into\ the\ grid,\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ then\ <strong>hold\ the\ board\ still\ for\ a\ few\ seconds\ until\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ pose\ is\ recorded.</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p><strong>You\ should\ be\ lifting\ your\ board\ above\ the\ table\ plane\ and\ tilting\ it\ in\ the\ air.\ Don't\ just\ keep\ it\ flat\ on\ the\ table!</strong></p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <iframe\ width=\"560\"\ height=\"315\"\ src=\"https://www.youtube-nocookie.com/embed/l1liP4_yiVM?si=DqgfNKq05EPBT3hT\"\ title=\"YouTube\ video\ player\"\ frameborder=\"0\"\ allow=\"accelerometer\;\ autoplay\;\ clipboard-write\;\ encrypted-media\;\ gyroscope\;\ picture-in-picture\;\ web-share\"\ referrerpolicy=\"strict-origin-when-cross-origin\"\ allowfullscreen></iframe>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p\ style=\"font-style:\ italic\;\ width:\ 100%\;\ text-align:\ center\;\">Example\ video\ of\ André\;s\ calibrating\ the\ folk0\ system\ (2x\ speed)</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Once\ you've\ recorded\ the\ first\ pose,\ <em>slowly\ drag\ the\ board\ around\ your\ space</em>,\ going\ slow\ enough\ for\ the\ projected\ AprilTags\ to\ catch\ up\ with\ the\ printed\ AprilTags\ and\ fit\ into\ the\ gaps\ on\ your\ board.\ When\ you've\ moved\ the\ board\ at\ least\ a\ full\ board-length\ away\ from\ the\ first\ pose,\ try\ to\ slant\ it\ 45\ degrees\ or\ so\ off\ the\ table\ and\ hold\ it\ still\ again\ to\ capture\ another\ pose.</p>\n\n\ \ \ \ \ \ \ \ \ \ <p>Repeat\ this\ process\ of\ dragging\ the\ board\ around\ and\n\ \ \ \ \ \ \ \ \ \ capturing\ a\ new\ pose.\ You'll\ need\ to\ record\ 10\ different\n\ \ \ \ \ \ \ \ \ \ poses\;\ try\ to\ slant\ the\ board\ and\ move\ it\ up\ and\ around\ to\n\ \ \ \ \ \ \ \ \ \ cover\ the\ projector/camera\ area\ as\ much\ as\ possible.\ Once\ 10\n\ \ \ \ \ \ \ \ \ \ poses\ are\ recorded,\ you'll\ see\ the\ results\ below.</p>\n\ \ \ \ \ \ \ \ <p>(If\ calibration\ gets\ into\ a\ bad/stuck\ state,\ feel\ free\ to\ click\ Start\ Calibration\ again.)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <details>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <summary>Troubleshooting</summary>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Look\ at\ ~/folk-calibration-poses\ to\ see\ images\ of\ the\ captured\ poses\ (maybe\ tags\ are\ distorted\ or\ washed\ out?).</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>You\ can\ try\ manually\ adjusting\ webcam\ settings\ if\ your\ poses\ are\ bad.\ (They\ should\ be\ immediately\ reflected\ in\ the\ camera\ preview\ once\ you\ refresh.)\ Folk\ tries\ to\ turn\ off\ autofocus\ by\ default,\ and\ you\ might\ also\ want\ to\ check\ that\ your\ camera\ actually\ has\ an\ exposure\ setting\ and\ focus\ setting.\ For\ example:</p>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <pre>\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --list-ctrls\n\nUser\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ brightness\ 0x00980900\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ contrast\ 0x00980901\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ saturation\ 0x00980902\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ white_balance_automatic\ 0x0098090c\ (bool)\ \ \ :\ default=1\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gain\ 0x00980913\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=0\ value=109\n\ \ \ \ \ \ \ \ \ \ \ power_line_frequency\ 0x00980918\ (menu)\ \ \ :\ min=0\ max=2\ default=2\ value=2\ (60\ Hz)\n\ \ \ \ \ \ white_balance_temperature\ 0x0098091a\ (int)\ \ \ \ :\ min=2000\ max=6500\ step=1\ default=4000\ value=3453\ flags=inactive\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ sharpness\ 0x0098091b\ (int)\ \ \ \ :\ min=0\ max=255\ step=1\ default=128\ value=128\n\ \ \ \ \ \ \ \ \ backlight_compensation\ 0x0098091c\ (int)\ \ \ \ :\ min=0\ max=1\ step=1\ default=0\ value=0\n\nCamera\ Controls\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ auto_exposure\ 0x009a0901\ (menu)\ \ \ :\ min=0\ max=3\ default=3\ value=3\ (Aperture\ Priority\ Mode)\n\ \ \ \ \ \ \ \ \ exposure_time_absolute\ 0x009a0902\ (int)\ \ \ \ :\ min=3\ max=2047\ step=1\ default=250\ value=83\ flags=inactive\n\ \ \ \ \ exposure_dynamic_framerate\ 0x009a0903\ (bool)\ \ \ :\ default=0\ value=1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pan_absolute\ 0x009a0908\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ tilt_absolute\ 0x009a0909\ (int)\ \ \ \ :\ min=-36000\ max=36000\ step=3600\ default=0\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ focus_absolute\ 0x009a090a\ (int)\ \ \ \ :\ min=0\ max=250\ step=5\ default=0\ value=30\n\ \ \ \ \ focus_automatic_continuous\ 0x009a090c\ (bool)\ \ \ :\ default=1\ value=0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ zoom_absolute\ 0x009a090d\ (int)\ \ \ \ :\ min=100\ max=500\ step=1\ default=100\ value=100\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=auto_exposure=1\ #\ to\ set\ them\ manually\ from\ terminal\n\\\$\ v4l2-ctl\ --device=/dev/video0\ --set-ctrl=exposure_time_absolute=25\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ </pre>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ <p>Camera\ needs\ to\ have\ auto_exposure\ and\ exposure_time_absolute\ settings\ listed\ for\ Folk\ to\ be\ able\ to\ set\ them.</p>\n\ \ \ \ \ \ \ \ \ \ \ \ </details>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Calibration\ results:</h3>\ <div\ id=\"calibration-report\"></div>\n\ \ \ \ \ \ \ \ \ \ \ \ <script>\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ const\ calibrationReportEl\ =\ document.getElementById('calibration-report')\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ folk.watchCollected(`/someone/\ claims\ the\ calibration\ report\ is\ /calibrationReport/`,\ reports\ =>\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ (reports.length\ ===\ 0)\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ \"<pre>Not\ calibrating\ yet.</pre>\"\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ return\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ calibrationReportEl.innerHTML\ =\ reports\[0\].calibrationReport\;\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \})\;\n\ \ \ \ \ \ \ \ \ \ \ \ </script>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>(For\ a\ good\ calibration,\ camera\ RMSE\ and\ projector\ RMSE\ should\ ideally\ be\ less\ than\ 1\ \[1\ to\ 2\ is\ OK\].\ Stereo\ RMSE\ should\ ideally\ be\ less\ than\ 5\ \[less\ than\ 10\ is\ OK\].)</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Calibration\ should\ be\ in\ place\ once\ you\ have\ 10\ poses!</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>If\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\n\ \ \ \ \ \ \ \ \ \ <li>\n\ \ \ \ \ \ \ \ \ \ \ \ <h3>Test\ calibration.</h3>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>The\ best\ way\ to\ test\ calibration\ is\ to\ look\ at\ your\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ printed\ program\ and\ see\ how\ well\ the\ projected\ outline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lines\ up\ with\ the\ physical\ edge\ of\ your\ program.</p>\n\n\ \ \ \ \ \ \ \ \ \ \ \ <p>Again,\ if\ you\ have\ a\ bad\ calibration,\ you\ can\ try\ just\n\ \ \ \ \ \ \ \ \ \ \ \ calibrating\ again.\ (Just\ scroll\ back\ up\ and\ click\ Start\n\ \ \ \ \ \ \ \ \ \ \ \ Calibration.\ You\ don't\ need\ to\ redo\ any\ of\ the\ steps\n\ \ \ \ \ \ \ \ \ \ \ \ before\ or\ after.)</p>\n\ \ \ \ \ \ \ \ \ \ </li>\n\ \ \ \ \ \ \ \ </ol>\n\ \ \ \ \ \ \ \ </article>\n\ \ \ \ \ \ </body>\n\ \ \ \ </html>\n\ \ \}\]\n {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}}}}
builtin-programs/calibrate/calibrate-page.folk wishes the web server handles route {/calibration-pose (
[ m1052:0 () ]
)builtin-programs/calibrate/calibrate-page.folk wishes the web server handles route {/calibration-poses/([^/]+)$} with handler {applyBlock \n\ \ \ \ set\ filename\ \"\$::env(HOME)/folk-calibration-poses/\$1\"\n\n\ \ \ \ set\ fsize\ \[file\ size\ \$filename\]\n\ \ \ \ set\ fd\ \[open\ \$filename\ r\]\n\ \ \ \ fconfigure\ \$fd\ -translation\ binary\n\ \ \ \ set\ body\ \[read\ \$fd\ \$fsize\]\n\ \ \ \ close\ \$fd\n\ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ image/jpeg\nContent-Length:\ \$fsize\n\n\"\ \\\n\ \ \ \ \ \ \ \ body\ \$body\n {{this builtin-programs/calibrate/calibrate-page.folk} {} {} {codeToPostScript {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}} {^codeToPostScript {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}} {{this builtin-programs/print/print.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {} {imageLib <C:cfileV8MUaU>} {} {saveDir /home/folk/folk-data/program} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} printLib <C:cfileDzXJHE> cc ::<reference.<C______>.00000000000000000002> ^codeToPostScript {{id code opts {marginsVar {}}} {
# All opts should be passed in as points (1/2834.65 of a meter).
lassign $opts(pageSize) PageWidth PageHeight
set tagInnerSideLength $opts(tagInnerSideLength)
set tagWidth [expr {$tagInnerSideLength * 10.0 / 6}]
set tagHeight $tagWidth
lassign $opts(margin) marginTop marginRight marginBottom marginLeft
set tagInset $opts(tagInset)
set lineHeight $opts(lineHeight)
# The calibration concat [s 0 0 s tx ty] maps our user coords to
# the printer's raw PS coords. Anything outside the raw
# [0,PageWidth]x[0,PageHeight] is clipped, so the effective
# printable area in user coords is smaller than the full page.
set calibScale [dict getdef $opts calibratedPrintScale 1.0]
lassign [dict getdef $opts calibratedPrintTranslation {0 0}] calibTx calibTy
set effTop [expr {($PageHeight - $calibTy) / $calibScale}]
set effBottom [expr {-$calibTy / $calibScale}]
set effLeft [expr {-$calibTx / $calibScale}]
set effRight [expr {($PageWidth - $calibTx) / $calibScale}]
# Effective margins, measured from the physical paper edge. The
# intent of marginTop/etc is "this far from the paper edge". If the
# printer's unprintable margin already exceeds that, clamp to the
# printable edge (rather than adding the two, which would push
# content way inward).
if {$marginsVar ne {}} {
upvar $marginsVar effMargins
} else {
set effMargins {}
}
set effMargins(top) [::math::max $marginTop [expr {$PageHeight - $effTop}]]
set effMargins(bottom) [::math::max $marginBottom $effBottom]
set effMargins(left) [::math::max $marginLeft $effLeft]
set effMargins(right) [::math::max $marginRight [expr {$PageWidth - $effRight}]]
set maxLines [expr {int(($PageHeight - $effMargins(top) - $effMargins(bottom)) / $lineHeight)}]
set lineNumbersRight [expr {$effMargins(left) + $opts(advance)*1.5}]
set lines [split $code "\n"]
set image [$printLib tagPsForId $id]
set outPages [list]
set lineIdx 0
while {[llength $lines] > 0} {
set pageLines [lrange $lines 0 $maxLines-1]
set lines [lreplace $lines 0 $maxLines-1]
set pageLineIdx 0
# The typesetting here is meant to exactly duplicate the
# layout in the editor.
lappend outPages [subst {
%!PS
<< /PageSize \[$PageWidth $PageHeight\] >> setpagedevice
\[$calibScale 0 0 $calibScale $calibTx $calibTy\] concat
/settextcolor {0 setgray} def
/NeomatrixCode findfont
$lineHeight scalefont
setfont
newpath
[join [lmap line $pageLines {
set line [string map {"\\" "\\\\" ")" "\\)" "(" "\\("} $line]
incr lineIdx
incr pageLineIdx
subst {
$lineNumbersRight [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
0.6 setgray ([format "% 3s" $lineIdx])
dup stringwidth pop neg 0 rmoveto
show
[+ $lineNumbersRight $opts(advance)] [expr {$PageHeight-$effMargins(top)-$pageLineIdx*$lineHeight}] moveto
settextcolor ($line) show
}
}] "\n"]
[expr {[llength $outPages] > 0 ? {} : [subst {
gsave
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-$tagInset}] translate
$tagWidth $tagHeight scale
$image
grestore
/Helvetica-Narrow findfont
7 scalefont
setfont
newpath
[expr {$PageWidth-$effMargins(right)-$tagWidth-$tagInset}] [expr {$PageHeight-$effMargins(top)-$tagHeight-14-$tagInset}] moveto
($id ([clock format [clock seconds] -format "%a, %d %b %Y, %r"])) show
}] }]
showpage
}]
}
return [join $outPages "\n"]
} {builtin-programs/print/print.folk 85}}}}}}}}}
builtin-programs/calibrate/calibrate-page.folk claims the calibration report is {
<p>Poses:</p> ()builtin-programs/calibrate/calibrate-page.folk claims the calibration report is {
<p>Poses:</p><ol>
<li style="padding-bottom: 1em">
RMSE 0.725728225238
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-0.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1367.43,391.922 1405.21,389.763 1402.77,354.724 1364.97,357.133 1367.43,391.922" fill="none" stroke="green" stroke-width="3" />
<text x="1367.431885" y="391.921936" fill="green" font-size="12">48601</text>
<polyline points="1520.25,382.996 1560.27,380.483 1556.39,345.479 1516.82,348.073 1520.25,382.996" fill="none" stroke="green" stroke-width="3" />
<text x="1520.251709" y="382.996368" fill="green" font-size="12">48603</text>
<polyline points="1296.98,465.833 1334.82,464.71 1332.75,428.698 1294.88,430.397 1296.98,465.833" fill="none" stroke="green" stroke-width="3" />
<text x="1296.983887" y="465.832520" fill="green" font-size="12">48604</text>
<polyline points="1448.43,459.266 1487.84,457.079 1484.45,420.929 1445.62,422.948 1448.43,459.266" fill="none" stroke="green" stroke-width="3" />
<text x="1448.426758" y="459.265656" fill="green" font-size="12">48606</text>
<polyline points="1377.01,533.713 1415.9,532.741 1413.31,495.927 1374.51,497.628 1377.01,533.713" fill="none" stroke="green" stroke-width="3" />
<text x="1377.006226" y="533.712585" fill="green" font-size="12">48609</text>
<polyline points="1533.44,527.498 1572.45,526.568 1569.05,489.148 1530.55,490.243 1533.44,527.498" fill="none" stroke="green" stroke-width="3" />
<text x="1533.442505" y="527.498169" fill="green" font-size="12">48611</text>
<polyline points="1306.24,608.615 1344.44,607.667 1341.83,571.074 1303.76,572.427 1306.24,608.615" fill="none" stroke="green" stroke-width="3" />
<text x="1306.240601" y="608.614990" fill="green" font-size="12">48612</text>
<polyline points="1460.86,603.967 1500.82,602.854 1497.58,565.594 1457.4,567.252 1460.86,603.967" fill="none" stroke="green" stroke-width="3" />
<text x="1460.857666" y="603.967041" fill="green" font-size="12">48614</text>
<polyline points="1388.15,680.365 1427.64,679.63 1424.39,642.253 1385.15,643.142 1388.15,680.365" fill="none" stroke="green" stroke-width="3" />
<text x="1388.146118" y="680.364746" fill="green" font-size="12">48617</text>
<polyline points="1547.08,676.827 1587.98,675.831 1583.96,637.826 1543.5,639.095 1547.08,676.827" fill="none" stroke="green" stroke-width="3" />
<text x="1547.084473" y="676.826904" fill="green" font-size="12">48619</text>
<polyline points="1293.4,397.174 1331.19,394.613 1328.71,359.331 1291.37,362.216 1293.4,397.174" fill="none" stroke="green" stroke-width="3" />
<text x="1293.403809" y="397.174408" fill="green" font-size="12">48600</text>
<polyline points="1443.13,388.179 1482.12,386.911 1479.02,350.824 1440.81,353.366 1443.13,388.179" fill="none" stroke="green" stroke-width="3" />
<text x="1443.130371" y="388.178741" fill="green" font-size="12">48602</text>
<polyline points="1372.4,463.839 1411.64,461.251 1408.59,425.34 1369.88,427.32 1372.4,463.839" fill="none" stroke="green" stroke-width="3" />
<text x="1372.398560" y="463.838928" fill="green" font-size="12">48605</text>
<polyline points="1526.84,455.811 1566.59,454.317 1563.77,416.481 1523.53,419.376 1526.84,455.811" fill="none" stroke="green" stroke-width="3" />
<text x="1526.837891" y="455.811432" fill="green" font-size="12">48607</text>
<polyline points="1302.11,537.349 1340.64,535.987 1338.15,499.382 1299.49,500.602 1302.11,537.349" fill="none" stroke="green" stroke-width="3" />
<text x="1302.109009" y="537.349243" fill="green" font-size="12">48608</text>
<polyline points="1454.54,531.718 1494.85,530.375 1491.63,493.079 1451.51,495.199 1454.54,531.718" fill="none" stroke="green" stroke-width="3" />
<text x="1454.544067" y="531.717834" fill="green" font-size="12">48610</text>
<polyline points="1383.69,606.713 1422.48,605.906 1419.35,568.597 1380.47,569.625 1383.69,606.713" fill="none" stroke="green" stroke-width="3" />
<text x="1383.686401" y="606.712585" fill="green" font-size="12">48613</text>
<polyline points="1540.74,601.987 1580.55,600.764 1576.89,563.217 1537.03,564.14 1540.74,601.987" fill="none" stroke="green" stroke-width="3" />
<text x="1540.743286" y="601.986816" fill="green" font-size="12">48615</text>
<polyline points="1311.35,682.408 1350.5,681.46 1347.78,643.882 1309.22,645.006 1311.35,682.408" fill="none" stroke="green" stroke-width="3" />
<text x="1311.354126" y="682.407532" fill="green" font-size="12">48616</text>
<polyline points="1467.18,679.633 1507.81,677.993 1504.76,640.16 1464.39,641.373 1467.18,679.633" fill="none" stroke="green" stroke-width="3" />
<text x="1467.177856" y="679.632935" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.89131853376
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-1.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1377.59,233.64 1417.54,229.659 1414.2,192.218 1374.62,196.259 1377.59,233.64" fill="none" stroke="green" stroke-width="3" />
<text x="1377.588257" y="233.639587" fill="green" font-size="12">48601</text>
<polyline points="1535.31,218.149 1575.98,214.535 1571.93,177.086 1531.56,180.869 1535.31,218.149" fill="none" stroke="green" stroke-width="3" />
<text x="1535.305908" y="218.149307" fill="green" font-size="12">48603</text>
<polyline points="1306.12,313.841 1345.08,310.326 1341.59,274.213 1303.34,277.205 1306.12,313.841" fill="none" stroke="green" stroke-width="3" />
<text x="1306.116943" y="313.840912" fill="green" font-size="12">48604</text>
<polyline points="1462.41,299.948 1502.63,296.395 1499.19,258.895 1459.29,262.52 1462.41,299.948" fill="none" stroke="green" stroke-width="3" />
<text x="1462.405518" y="299.948456" fill="green" font-size="12">48606</text>
<polyline points="1390.1,380.932 1429.53,377.934 1426.24,340.646 1386.85,344.056 1390.1,380.932" fill="none" stroke="green" stroke-width="3" />
<text x="1390.102661" y="380.931671" fill="green" font-size="12">48609</text>
<polyline points="1549.18,367.838 1588.58,365.236 1584.65,327.663 1546.49,329.953 1549.18,367.838" fill="none" stroke="green" stroke-width="3" />
<text x="1549.179443" y="367.838379" fill="green" font-size="12">48611</text>
<polyline points="1318.51,462.043 1358.46,459.202 1354.72,421.314 1315.22,424.358 1318.51,462.043" fill="none" stroke="green" stroke-width="3" />
<text x="1318.508179" y="462.043243" fill="green" font-size="12">48612</text>
<polyline points="1476.8,449.947 1516.71,447.297 1512.82,409.048 1472.77,412.225 1476.8,449.947" fill="none" stroke="green" stroke-width="3" />
<text x="1476.802612" y="449.946777" fill="green" font-size="12">48614</text>
<polyline points="1404.71,531.414 1445.43,528.575 1441.9,490.051 1400.94,492.917 1404.71,531.414" fill="none" stroke="green" stroke-width="3" />
<text x="1404.714844" y="531.413879" fill="green" font-size="12">48617</text>
<polyline points="1566.05,520.226 1606.48,517.6 1601.71,478.767 1560.93,481.633 1566.05,520.226" fill="none" stroke="green" stroke-width="3" />
<text x="1566.048706" y="520.226074" fill="green" font-size="12">48619</text>
<polyline points="1299.98,243.184 1339.74,239.226 1336.86,201.814 1296.94,205.821 1299.98,243.184" fill="none" stroke="green" stroke-width="3" />
<text x="1299.982056" y="243.184250" fill="green" font-size="12">48600</text>
<polyline points="1456.19,227.932 1496.75,224.579 1493.37,186.521 1452.81,190.511 1456.19,227.932" fill="none" stroke="green" stroke-width="3" />
<text x="1456.190552" y="227.932159" fill="green" font-size="12">48602</text>
<polyline points="1381.08,272.196 1383.98,309.481 1423.91,305.67 1420.3,268.409 1381.08,272.196" fill="none" stroke="green" stroke-width="3" />
<text x="1381.081299" y="272.196045" fill="green" font-size="12">48605</text>
<polyline points="1542.88,294.537 1582.19,292.009 1578.75,254.058 1539.62,256.704 1542.88,294.537" fill="none" stroke="green" stroke-width="3" />
<text x="1542.879883" y="294.537292" fill="green" font-size="12">48607</text>
<polyline points="1312.41,390.445 1352.47,386.979 1349.09,349.085 1309.4,353.059 1312.41,390.445" fill="none" stroke="green" stroke-width="3" />
<text x="1312.406006" y="390.445038" fill="green" font-size="12">48608</text>
<polyline points="1469.6,377.691 1510.82,373.957 1506.69,336.139 1466.97,339.796 1469.6,377.691" fill="none" stroke="green" stroke-width="3" />
<text x="1469.599854" y="377.690796" fill="green" font-size="12">48610</text>
<polyline points="1394.12,420.463 1397.87,459 1438.66,455.776 1434.26,417.358 1394.12,420.463" fill="none" stroke="green" stroke-width="3" />
<text x="1394.115112" y="420.463196" fill="green" font-size="12">48613</text>
<polyline points="1557.11,447.186 1598.87,444.504 1594.43,405.246 1553.89,408.197 1557.11,447.186" fill="none" stroke="green" stroke-width="3" />
<text x="1557.106689" y="447.186432" fill="green" font-size="12">48615</text>
<polyline points="1325.91,539.723 1366.12,537.195 1362.37,498.437 1322.23,501.476 1325.91,539.723" fill="none" stroke="green" stroke-width="3" />
<text x="1325.910889" y="539.723450" fill="green" font-size="12">48616</text>
<polyline points="1485.65,528.902 1527.6,526.066 1523.4,486.462 1481.83,489.707 1485.65,528.902" fill="none" stroke="green" stroke-width="3" />
<text x="1485.648682" y="528.901550" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.12427806234
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-2.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1480.65,85.9842 1536.13,82.8197 1538.86,22.7911 1483.49,26.2682 1480.65,85.9842" fill="none" stroke="green" stroke-width="3" />
<text x="1480.648926" y="85.984230" fill="green" font-size="12">48601</text>
<polyline points="1365.31,209.826 1421.08,206.09 1423,147.409 1367.77,150.873 1365.31,209.826" fill="none" stroke="green" stroke-width="3" />
<text x="1365.312988" y="209.825806" fill="green" font-size="12">48604</text>
<polyline points="1581.29,195.975 1636.13,193.27 1640.51,134.807 1585.92,137.737 1581.29,195.975" fill="none" stroke="green" stroke-width="3" />
<text x="1581.291260" y="195.974930" fill="green" font-size="12">48606</text>
<polyline points="1467.73,311.926 1520.55,308.732 1524.37,254.145 1470.83,257.484 1467.73,311.926" fill="none" stroke="green" stroke-width="3" />
<text x="1467.725464" y="311.925690" fill="green" font-size="12">48609</text>
<polyline points="1678.11,299.656 1728.07,296.963 1733.85,242.453 1684.11,245.028 1678.11,299.656" fill="none" stroke="green" stroke-width="3" />
<text x="1678.112183" y="299.655853" fill="green" font-size="12">48611</text>
<polyline points="1358.84,424.565 1411.06,421.179 1412.72,368.966 1360.27,372.199 1358.84,424.565" fill="none" stroke="green" stroke-width="3" />
<text x="1358.841064" y="424.564758" fill="green" font-size="12">48612</text>
<polyline points="1565.01,411.651 1615.94,408.256 1620.92,355.985 1568.79,358.936 1565.01,411.651" fill="none" stroke="green" stroke-width="3" />
<text x="1565.013916" y="411.650513" fill="green" font-size="12">48614</text>
<polyline points="1456.93,518.885 1508.52,515.552 1511.41,465.146 1459.29,468.313 1456.93,518.885" fill="none" stroke="green" stroke-width="3" />
<text x="1456.933105" y="518.884766" fill="green" font-size="12">48617</text>
<polyline points="1656.81,506.011 1707.05,503.156 1711.7,452.871 1661.05,455.896 1656.81,506.011" fill="none" stroke="green" stroke-width="3" />
<text x="1656.806152" y="506.011230" fill="green" font-size="12">48619</text>
<polyline points="1369.52,92.6488 1426.72,87.9975 1428.33,28.0723 1372.39,30.325 1369.52,92.6488" fill="none" stroke="green" stroke-width="3" />
<text x="1369.518433" y="92.648804" fill="green" font-size="12">48600</text>
<polyline points="1590.64,78.1485 1645.18,75.5008 1650.33,15.4836 1595.3,17.8232 1590.64,78.1485" fill="none" stroke="green" stroke-width="3" />
<text x="1590.636230" y="78.148476" fill="green" font-size="12">48602</text>
<polyline points="1473.29,202.666 1529.04,199.092 1532.44,140.083 1476.36,142.849 1473.29,202.666" fill="none" stroke="green" stroke-width="3" />
<text x="1473.294922" y="202.666061" fill="green" font-size="12">48605</text>
<polyline points="1687.9,188.728 1740.14,186.814 1747.22,127.192 1692.82,129.918 1687.9,188.728" fill="none" stroke="green" stroke-width="3" />
<text x="1687.903442" y="188.728394" fill="green" font-size="12">48607</text>
<polyline points="1361.93,318.369 1415.51,314.445 1418.56,259.148 1363.44,263.838 1361.93,318.369" fill="none" stroke="green" stroke-width="3" />
<text x="1361.929688" y="318.369263" fill="green" font-size="12">48608</text>
<polyline points="1572.5,305.586 1625.16,301.928 1630.32,247.095 1577.11,250.361 1572.5,305.586" fill="none" stroke="green" stroke-width="3" />
<text x="1572.501587" y="305.586060" fill="green" font-size="12">48610</text>
<polyline points="1462.31,417.067 1514.5,414.531 1517.47,361.646 1465.07,364.23 1462.31,417.067" fill="none" stroke="green" stroke-width="3" />
<text x="1462.307617" y="417.067352" fill="green" font-size="12">48613</text>
<polyline points="1666.8,404.402 1716.85,401.537 1721.93,349.596 1672.44,351.307 1666.8,404.402" fill="none" stroke="green" stroke-width="3" />
<text x="1666.799194" y="404.401581" fill="green" font-size="12">48615</text>
<polyline points="1355.68,523.805 1407.25,521.064 1409.44,470.152 1356.13,473.535 1355.68,523.805" fill="none" stroke="green" stroke-width="3" />
<text x="1355.683105" y="523.804565" fill="green" font-size="12">48616</text>
<polyline points="1557.03,511.571 1609.12,507.885 1612.78,457.055 1561.36,460.423 1557.03,511.571" fill="none" stroke="green" stroke-width="3" />
<text x="1557.027588" y="511.571320" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.96923416025
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-3.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1222.11,348.785 1216.37,300.245 1166.46,306.593 1172.06,355.129 1222.11,348.785" fill="none" stroke="green" stroke-width="3" />
<text x="1222.111084" y="348.784912" fill="green" font-size="12">48601</text>
<polyline points="1199.85,158.204 1193.67,110.035 1144,116.397 1149.26,164.909 1199.85,158.204" fill="none" stroke="green" stroke-width="3" />
<text x="1199.847046" y="158.204208" fill="green" font-size="12">48603</text>
<polyline points="1338.62,434.53 1331.86,384.154 1279.36,390.333 1285.77,440.204 1338.62,434.53" fill="none" stroke="green" stroke-width="3" />
<text x="1338.622192" y="434.530487" fill="green" font-size="12">48604</text>
<polyline points="1311.47,240.157 1305.32,190.902 1253.95,197.879 1260.24,246.411 1311.47,240.157" fill="none" stroke="green" stroke-width="3" />
<text x="1311.468262" y="240.157288" fill="green" font-size="12">48606</text>
<polyline points="1428.08,322.549 1420.25,274.269 1368.6,281.004 1375.68,328.877 1428.08,322.549" fill="none" stroke="green" stroke-width="3" />
<text x="1428.077271" y="322.549194" fill="green" font-size="12">48609</text>
<polyline points="1399.74,131.376 1391.64,85.3372 1341.11,91.8847 1348.33,138.087 1399.74,131.376" fill="none" stroke="green" stroke-width="3" />
<text x="1399.739502" y="131.376297" fill="green" font-size="12">48611</text>
<polyline points="1550.77,409.181 1541.71,358.775 1489.09,365.109 1495.86,415.912 1550.77,409.181" fill="none" stroke="green" stroke-width="3" />
<text x="1550.766846" y="409.180939" fill="green" font-size="12">48612</text>
<polyline points="1517.27,213.761 1508.71,165.099 1456.42,171.521 1463.94,220.6 1517.27,213.761" fill="none" stroke="green" stroke-width="3" />
<text x="1517.266602" y="213.760712" fill="green" font-size="12">48614</text>
<polyline points="1639.27,297.008 1629.77,248.022 1577.12,254.516 1586.11,303.228 1639.27,297.008" fill="none" stroke="green" stroke-width="3" />
<text x="1639.266846" y="297.007874" fill="green" font-size="12">48617</text>
<polyline points="1602.3,106.652 1592.92,59.6051 1542.63,65.8528 1550.4,112.725 1602.3,106.652" fill="none" stroke="green" stroke-width="3" />
<text x="1602.301147" y="106.652153" fill="green" font-size="12">48619</text>
<polyline points="1236.49,449.318 1229.8,398.073 1177.8,404.405 1183.69,455.228 1236.49,449.318" fill="none" stroke="green" stroke-width="3" />
<text x="1236.492432" y="449.318146" fill="green" font-size="12">48600</text>
<polyline points="1212.46,253.816 1207.14,204.864 1155.54,211.796 1161.42,260.15 1212.46,253.816" fill="none" stroke="green" stroke-width="3" />
<text x="1212.459473" y="253.815598" fill="green" font-size="12">48602</text>
<polyline points="1325.86,337.833 1318.71,289.046 1267.29,295.762 1274.16,344.212 1325.86,337.833" fill="none" stroke="green" stroke-width="3" />
<text x="1325.864990" y="337.833160" fill="green" font-size="12">48605</text>
<polyline points="1301.37,146.699 1294.98,99.184 1244.21,105.125 1249.89,152.637 1301.37,146.699" fill="none" stroke="green" stroke-width="3" />
<text x="1301.373169" y="146.699203" fill="green" font-size="12">48607</text>
<polyline points="1445.37,424.986 1437.86,373.319 1384.36,379.553 1391.05,431.454 1445.37,424.986" fill="none" stroke="green" stroke-width="3" />
<text x="1445.368042" y="424.986145" fill="green" font-size="12">48608</text>
<polyline points="1415.36,229.485 1408.3,180.035 1355.68,186.583 1362.75,235.348 1415.36,229.485" fill="none" stroke="green" stroke-width="3" />
<text x="1415.355225" y="229.484650" fill="green" font-size="12">48610</text>
<polyline points="1535.19,311.401 1525.94,263.202 1472.87,269.811 1482.18,317.866 1535.19,311.401" fill="none" stroke="green" stroke-width="3" />
<text x="1535.192505" y="311.400970" fill="green" font-size="12">48613</text>
<polyline points="1503.44,121.381 1494.25,74.7291 1443.12,81.2754 1450.7,127.522 1503.44,121.381" fill="none" stroke="green" stroke-width="3" />
<text x="1503.442139" y="121.380783" fill="green" font-size="12">48615</text>
<polyline points="1659.89,399.384 1649.84,348.796 1596,354.982 1604.8,406.215 1659.89,399.384" fill="none" stroke="green" stroke-width="3" />
<text x="1659.892212" y="399.384186" fill="green" font-size="12">48616</text>
<polyline points="1622.02,204.145 1613.07,154.467 1560.33,160.729 1568.57,210.357 1622.02,204.145" fill="none" stroke="green" stroke-width="3" />
<text x="1622.018433" y="204.144791" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.60197092768
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-4.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1161.82,600.762 1163.24,562.024 1120.93,563.719 1120.48,602.199 1161.82,600.762" fill="none" stroke="green" stroke-width="3" />
<text x="1161.815552" y="600.761658" fill="green" font-size="12">48601</text>
<polyline points="1167.4,439.41 1168.94,395.168 1123.94,397.177 1122.79,441.483 1167.4,439.41" fill="none" stroke="green" stroke-width="3" />
<text x="1167.404541" y="439.410339" fill="green" font-size="12">48603</text>
<polyline points="1241.05,672.531 1243.32,635.811 1201.96,636.943 1200.22,673.816 1241.05,672.531" fill="none" stroke="green" stroke-width="3" />
<text x="1241.052490" y="672.530945" fill="green" font-size="12">48604</text>
<polyline points="1250.24,519.469 1253.13,477.784 1208.7,479.424 1206.81,521.516 1250.24,519.469" fill="none" stroke="green" stroke-width="3" />
<text x="1250.237061" y="519.468994" fill="green" font-size="12">48606</text>
<polyline points="1329.27,595.172 1332.63,555.745 1289.95,557.359 1286.86,596.405 1329.27,595.172" fill="none" stroke="green" stroke-width="3" />
<text x="1329.272949" y="595.172302" fill="green" font-size="12">48609</text>
<polyline points="1345.42,431.92 1348.67,386.653 1303.43,388.489 1300.43,433.823 1345.42,431.92" fill="none" stroke="green" stroke-width="3" />
<text x="1345.424316" y="431.919800" fill="green" font-size="12">48611</text>
<polyline points="1405.2,668.071 1409.6,630.439 1367.86,631.949 1363.37,668.476 1405.2,668.071" fill="none" stroke="green" stroke-width="3" />
<text x="1405.200684" y="668.071045" fill="green" font-size="12">48612</text>
<polyline points="1424.6,512.735 1429.51,470.11 1384.81,472.208 1379.89,514.238 1424.6,512.735" fill="none" stroke="green" stroke-width="3" />
<text x="1424.596436" y="512.734863" fill="green" font-size="12">48614</text>
<polyline points="1500.18,589.614 1506.08,549.731 1462.4,551.368 1457.02,590.926 1500.18,589.614" fill="none" stroke="green" stroke-width="3" />
<text x="1500.176636" y="589.614075" fill="green" font-size="12">48617</text>
<polyline points="1525.06,423.736 1531.93,378.371 1485.98,380.417 1479.56,425.79 1525.06,423.736" fill="none" stroke="green" stroke-width="3" />
<text x="1525.058838" y="423.735840" fill="green" font-size="12">48619</text>
<polyline points="1157.73,676.412 1159.24,639.123 1118.03,639.842 1117.27,677.301 1157.73,676.412" fill="none" stroke="green" stroke-width="3" />
<text x="1157.728149" y="676.412109" fill="green" font-size="12">48600</text>
<polyline points="1163.27,522.951 1164.35,480.564 1119.99,481.755 1119.64,524.188 1163.27,522.951" fill="none" stroke="green" stroke-width="3" />
<text x="1163.265625" y="522.951355" fill="green" font-size="12">48602</text>
<polyline points="1201.27,599.938 1243.42,599.076 1245.84,560.111 1203.13,561.096 1201.27,599.938" fill="none" stroke="green" stroke-width="3" />
<text x="1201.270752" y="599.937561" fill="green" font-size="12">48605</text>
<polyline points="1254.38,435.44 1256.47,390.93 1211.25,392.006 1208.93,436.124 1254.38,435.44" fill="none" stroke="green" stroke-width="3" />
<text x="1254.376343" y="435.440247" fill="green" font-size="12">48607</text>
<polyline points="1320.73,671.877 1324.38,634.33 1282.55,635.446 1278.99,673.79 1320.73,671.877" fill="none" stroke="green" stroke-width="3" />
<text x="1320.725586" y="671.876770" fill="green" font-size="12">48608</text>
<polyline points="1335.12,517.578 1339.2,475.335 1294.03,476.139 1290.77,518.369 1335.12,517.578" fill="none" stroke="green" stroke-width="3" />
<text x="1335.116821" y="517.577820" fill="green" font-size="12">48610</text>
<polyline points="1369.9,595.453 1413.16,593.947 1417.28,554.43 1373.91,555.237 1369.9,595.453" fill="none" stroke="green" stroke-width="3" />
<text x="1369.902954" y="595.453003" fill="green" font-size="12">48613</text>
<polyline points="1433.58,429.079 1438.58,383.783 1391.77,385.845 1387.74,430.044 1433.58,429.079" fill="none" stroke="green" stroke-width="3" />
<text x="1433.579224" y="429.078918" fill="green" font-size="12">48615</text>
<polyline points="1487.4,667.221 1492.82,629.765 1450.28,631.479 1444.67,668.2 1487.4,667.221" fill="none" stroke="green" stroke-width="3" />
<text x="1487.397583" y="667.221069" fill="green" font-size="12">48616</text>
<polyline points="1510.94,511.321 1517.89,468.175 1472.14,469.854 1465.75,512.261 1510.94,511.321" fill="none" stroke="green" stroke-width="3" />
<text x="1510.942993" y="511.321289" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.01227215325
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-5.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="961.526,180.89 998.663,173.187 994.492,137.17 957.514,145.294 961.526,180.89" fill="none" stroke="green" stroke-width="3" />
<text x="961.526062" y="180.890030" fill="green" font-size="12">48601</text>
<polyline points="1111.38,149.231 1150.94,141.91 1145.98,104.73 1106.94,113.302 1111.38,149.231" fill="none" stroke="green" stroke-width="3" />
<text x="1111.380981" y="149.230835" fill="green" font-size="12">48603</text>
<polyline points="897.504,265.618 933.629,258.776 929.834,223.057 893.547,230.007 897.504,265.618" fill="none" stroke="green" stroke-width="3" />
<text x="897.504028" y="265.617676" fill="green" font-size="12">48604</text>
<polyline points="1044.22,237.68 1082.99,230.329 1078.23,193.237 1039.66,200.734 1044.22,237.68" fill="none" stroke="green" stroke-width="3" />
<text x="1044.215210" y="237.679565" fill="green" font-size="12">48606</text>
<polyline points="978.373,323.581 1015.69,317.462 1011.31,280.87 973.993,287.962 978.373,323.581" fill="none" stroke="green" stroke-width="3" />
<text x="978.372559" y="323.581116" fill="green" font-size="12">48609</text>
<polyline points="1130.85,296.856 1170.36,290.62 1165.28,253.041 1125.9,259.465 1130.85,296.856" fill="none" stroke="green" stroke-width="3" />
<text x="1130.848511" y="296.855865" fill="green" font-size="12">48611</text>
<polyline points="912.622,409.819 949.752,403.973 945.61,366.796 909.083,373.39 912.622,409.819" fill="none" stroke="green" stroke-width="3" />
<text x="912.621643" y="409.819275" fill="green" font-size="12">48612</text>
<polyline points="1062.53,385.34 1101.74,378.891 1096.73,341.298 1058.06,348.126 1062.53,385.34" fill="none" stroke="green" stroke-width="3" />
<text x="1062.534424" y="385.340088" fill="green" font-size="12">48614</text>
<polyline points="994.766,472.561 1033.85,466.87 1029.12,428.338 990.725,434.344 994.766,472.561" fill="none" stroke="green" stroke-width="3" />
<text x="994.765564" y="472.561249" fill="green" font-size="12">48617</text>
<polyline points="1150.67,449.554 1191.84,443.556 1186.21,404.371 1145.66,410.473 1150.67,449.554" fill="none" stroke="green" stroke-width="3" />
<text x="1150.667725" y="449.554413" fill="green" font-size="12">48619</text>
<polyline points="889.985,199.787 926.488,191.674 922.555,156.222 886.374,163.982 889.985,199.787" fill="none" stroke="green" stroke-width="3" />
<text x="889.984741" y="199.787430" fill="green" font-size="12">48600</text>
<polyline points="1034.97,168.698 1073.74,160.712 1068.65,124.181 1030.37,132.357 1034.97,168.698" fill="none" stroke="green" stroke-width="3" />
<text x="1034.971924" y="168.697723" fill="green" font-size="12">48602</text>
<polyline points="1007.71,248.093 1003.32,211.708 965.542,219.252 970.112,255.544 1007.71,248.093" fill="none" stroke="green" stroke-width="3" />
<text x="1007.705933" y="248.093491" fill="green" font-size="12">48605</text>
<polyline points="1120.36,225.086 1160.32,218.317 1155.17,180.507 1115.31,187.178 1120.36,225.086" fill="none" stroke="green" stroke-width="3" />
<text x="1120.361816" y="225.086212" fill="green" font-size="12">48607</text>
<polyline points="906.624,340.189 942.87,333.021 938.392,297.048 902.169,304.013 906.624,340.189" fill="none" stroke="green" stroke-width="3" />
<text x="906.624146" y="340.189362" fill="green" font-size="12">48608</text>
<polyline points="1053.66,313.242 1092.29,306.299 1087.53,269.16 1048.9,276.496 1053.66,313.242" fill="none" stroke="green" stroke-width="3" />
<text x="1053.658569" y="313.241547" fill="green" font-size="12">48610</text>
<polyline points="1026.17,393.921 1021.38,356.461 983.373,362.746 987.669,399.949 1026.17,393.921" fill="none" stroke="green" stroke-width="3" />
<text x="1026.171143" y="393.921082" fill="green" font-size="12">48613</text>
<polyline points="1141.12,373.867 1181.45,367.684 1175.56,329.788 1136.04,335.906 1141.12,373.867" fill="none" stroke="green" stroke-width="3" />
<text x="1141.118408" y="373.867371" fill="green" font-size="12">48615</text>
<polyline points="922.38,485.614 960.985,480.247 955.976,441.965 918.181,447.772 922.38,485.614" fill="none" stroke="green" stroke-width="3" />
<text x="922.379578" y="485.613617" fill="green" font-size="12">48616</text>
<polyline points="1073,463.024 1113.5,456.693 1107.94,417.233 1068.06,423.802 1073,463.024" fill="none" stroke="green" stroke-width="3" />
<text x="1073.001709" y="463.023590" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.0423236365
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-6.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="973.478,90.7454 1019.58,88.3579 1018.22,35.5119 971.393,38.0315 973.478,90.7454" fill="none" stroke="green" stroke-width="3" />
<text x="973.477661" y="90.745377" fill="green" font-size="12">48601</text>
<polyline points="1156.18,80.3913 1202.45,77.7942 1204.51,25.9644 1158.14,27.9488 1156.18,80.3913" fill="none" stroke="green" stroke-width="3" />
<text x="1156.181641" y="80.391281" fill="green" font-size="12">48603</text>
<polyline points="889.397,195.436 934.235,192.825 931.088,143.462 885.473,146.002 889.397,195.436" fill="none" stroke="green" stroke-width="3" />
<text x="889.396729" y="195.435806" fill="green" font-size="12">48604</text>
<polyline points="1065.12,184.975 1109.74,182.464 1110.23,133.209 1065.1,135.902 1065.12,184.975" fill="none" stroke="green" stroke-width="3" />
<text x="1065.120605" y="184.974594" fill="green" font-size="12">48606</text>
<polyline points="981.455,281.021 1023.61,278.444 1022.98,233.625 979.548,236.218 981.455,281.021" fill="none" stroke="green" stroke-width="3" />
<text x="981.454956" y="281.020996" fill="green" font-size="12">48609</text>
<polyline points="1150.32,270.641 1191.79,267.688 1194.59,222.833 1151.83,226.033 1150.32,270.641" fill="none" stroke="green" stroke-width="3" />
<text x="1150.322266" y="270.640564" fill="green" font-size="12">48611</text>
<polyline points="903.591,370.807 944.803,368.034 941.782,326.576 900.361,329.095 903.591,370.807" fill="none" stroke="green" stroke-width="3" />
<text x="903.591309" y="370.806976" fill="green" font-size="12">48612</text>
<polyline points="1066.02,360.52 1107.08,357.742 1107.17,316.263 1066.42,318.74 1066.02,360.52" fill="none" stroke="green" stroke-width="3" />
<text x="1066.020996" y="360.519623" fill="green" font-size="12">48614</text>
<polyline points="987.993,444.139 1027.96,441.847 1026.91,402.713 987.215,405.585 987.993,444.139" fill="none" stroke="green" stroke-width="3" />
<text x="987.993103" y="444.138885" fill="green" font-size="12">48617</text>
<polyline points="1144.6,433.874 1183.83,430.97 1185.66,391.943 1146.12,394.862 1144.6,433.874" fill="none" stroke="green" stroke-width="3" />
<text x="1144.602783" y="433.873840" fill="green" font-size="12">48619</text>
<polyline points="879.565,98.8311 926.215,95.174 922.728,41.9485 875.174,44.9588 879.565,98.8311" fill="none" stroke="green" stroke-width="3" />
<text x="879.565063" y="98.831100" fill="green" font-size="12">48600</text>
<polyline points="1062.45,87.6651 1108.79,85.0553 1109.04,31.7388 1062.93,34.4441 1062.45,87.6651" fill="none" stroke="green" stroke-width="3" />
<text x="1062.445923" y="87.665062" fill="green" font-size="12">48602</text>
<polyline points="973.271,143.106 975.749,192.658 1021.54,190.782 1018.92,140.877 973.271,143.106" fill="none" stroke="green" stroke-width="3" />
<text x="973.270996" y="143.105530" fill="green" font-size="12">48605</text>
<polyline points="1150.81,180.724 1195.43,177.985 1197.8,127.599 1151.8,131.887 1150.81,180.724" fill="none" stroke="green" stroke-width="3" />
<text x="1150.805542" y="180.724335" fill="green" font-size="12">48607</text>
<polyline points="895.314,289.226 938.358,286.46 935.249,240.887 891.718,243.977 895.314,289.226" fill="none" stroke="green" stroke-width="3" />
<text x="895.314270" y="289.225830" fill="green" font-size="12">48608</text>
<polyline points="1064.24,278.831 1106.52,275.831 1107.61,230.559 1063.49,233.553 1064.24,278.831" fill="none" stroke="green" stroke-width="3" />
<text x="1064.236572" y="278.830505" fill="green" font-size="12">48610</text>
<polyline points="982.016,326.395 984.393,368.503 1025.03,366.2 1023.77,323.807 982.016,326.395" fill="none" stroke="green" stroke-width="3" />
<text x="982.015869" y="326.394714" fill="green" font-size="12">48613</text>
<polyline points="1146.14,356.945 1186.64,354.646 1188.53,312.808 1147.28,314.565 1146.14,356.945" fill="none" stroke="green" stroke-width="3" />
<text x="1146.137329" y="356.945221" fill="green" font-size="12">48615</text>
<polyline points="908.726,452.526 949.157,450.607 946.694,410.507 905.706,413.912 908.726,452.526" fill="none" stroke="green" stroke-width="3" />
<text x="908.725525" y="452.526123" fill="green" font-size="12">48616</text>
<polyline points="1065.63,441.997 1105.94,439.001 1105.52,399.376 1065.62,402.341 1065.63,441.997" fill="none" stroke="green" stroke-width="3" />
<text x="1065.630981" y="441.996979" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.41663092406
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-7.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="930.949,336.128 970.724,329.257 967.532,303.302 928.905,310.056 930.949,336.128" fill="none" stroke="green" stroke-width="3" />
<text x="930.948975" y="336.128265" fill="green" font-size="12">48601</text>
<polyline points="1091.46,309.351 1132.33,302.97 1125.3,276.903 1085.33,283.652 1091.46,309.351" fill="none" stroke="green" stroke-width="3" />
<text x="1091.457397" y="309.351135" fill="green" font-size="12">48603</text>
<polyline points="853.659,405.51 894.607,398.498 893.468,369.617 852.656,376.193 853.659,405.51" fill="none" stroke="green" stroke-width="3" />
<text x="853.658752" y="405.510284" fill="green" font-size="12">48604</text>
<polyline points="1020.03,380.388 1062.75,374.629 1056.75,344.84 1015.53,351.817 1020.03,380.388" fill="none" stroke="green" stroke-width="3" />
<text x="1020.033813" y="380.388397" fill="green" font-size="12">48606</text>
<polyline points="941.885,454.018 986.398,446.855 982.146,415.507 938.896,422.11 941.885,454.018" fill="none" stroke="green" stroke-width="3" />
<text x="941.884705" y="454.018036" fill="green" font-size="12">48609</text>
<polyline points="1119.2,430.998 1164.85,424.474 1155.94,393.054 1111.96,398.352 1119.2,430.998" fill="none" stroke="green" stroke-width="3" />
<text x="1119.195923" y="430.997711" fill="green" font-size="12">48611</text>
<polyline points="855.905,537.082 902.737,530.845 900.828,494.607 855.529,502.06 855.905,537.082" fill="none" stroke="green" stroke-width="3" />
<text x="855.905457" y="537.082336" fill="green" font-size="12">48612</text>
<polyline points="1041.35,509.092 1089.7,502.621 1082.03,467.625 1035.66,473.14 1041.35,509.092" fill="none" stroke="green" stroke-width="3" />
<text x="1041.345215" y="509.091980" fill="green" font-size="12">48614</text>
<polyline points="955.284,598.862 1005.15,591.779 999.933,552.092 951.71,559.679 955.284,598.862" fill="none" stroke="green" stroke-width="3" />
<text x="955.283936" y="598.861938" fill="green" font-size="12">48617</text>
<polyline points="1155.16,570.688 1206.05,564.145 1194.97,525.254 1145.05,531.716 1155.16,570.688" fill="none" stroke="green" stroke-width="3" />
<text x="1155.157227" y="570.688110" fill="green" font-size="12">48619</text>
<polyline points="850.153,347.147 890.231,340.158 888.217,313.861 849.431,320.008 850.153,347.147" fill="none" stroke="green" stroke-width="3" />
<text x="850.153198" y="347.147217" fill="green" font-size="12">48600</text>
<polyline points="1009.68,321.059 1050.36,314.884 1045.06,288.546 1005.12,295.252 1009.68,321.059" fill="none" stroke="green" stroke-width="3" />
<text x="1009.680237" y="321.058594" fill="green" font-size="12">48602</text>
<polyline points="932.092,362.031 934.828,391.16 977.715,384.745 973.484,355.744 932.092,362.031" fill="none" stroke="green" stroke-width="3" />
<text x="932.091919" y="362.031342" fill="green" font-size="12">48605</text>
<polyline points="1103.99,365.027 1147.3,359.806 1139.06,329.696 1097.29,335.698 1103.99,365.027" fill="none" stroke="green" stroke-width="3" />
<text x="1103.990112" y="365.026520" fill="green" font-size="12">48607</text>
<polyline points="853.459,466.811 898.051,459.668 895.612,426.744 852.913,433.881 853.459,466.811" fill="none" stroke="green" stroke-width="3" />
<text x="853.459473" y="466.811462" fill="green" font-size="12">48608</text>
<polyline points="1029.29,440.778 1074.8,434.456 1068.16,402.347 1023.87,408.415 1029.29,440.778" fill="none" stroke="green" stroke-width="3" />
<text x="1029.286255" y="440.778168" fill="green" font-size="12">48610</text>
<polyline points="943.878,485.345 947.117,521.778 995.351,515.521 990.469,478.575 943.878,485.345" fill="none" stroke="green" stroke-width="3" />
<text x="943.878113" y="485.345337" fill="green" font-size="12">48613</text>
<polyline points="1135.34,495.411 1184.02,489.054 1173.78,453.439 1126.53,459.801 1135.34,495.411" fill="none" stroke="green" stroke-width="3" />
<text x="1135.341919" y="495.410980" fill="green" font-size="12">48615</text>
<polyline points="856.711,611.316 906.285,605.007 904.167,565.118 855.684,571.842 856.711,611.316" fill="none" stroke="green" stroke-width="3" />
<text x="856.710999" y="611.316040" fill="green" font-size="12">48616</text>
<polyline points="1054.05,584.49 1104.97,577.226 1096.61,537.481 1047.28,544.291 1054.05,584.49" fill="none" stroke="green" stroke-width="3" />
<text x="1054.046997" y="584.490234" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.7736504896
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-8.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="617.968,158.738 672.279,157.611 666.108,108.714 612.278,108.921 617.968,158.738" fill="none" stroke="green" stroke-width="3" />
<text x="617.967773" y="158.737991" fill="green" font-size="12">48601</text>
<polyline points="822.704,157.752 871.943,155.121 865.329,109.701 816.837,109.685 822.704,157.752" fill="none" stroke="green" stroke-width="3" />
<text x="822.703674" y="157.752472" fill="green" font-size="12">48603</text>
<polyline points="518.562,260.514 575.345,258.715 570.413,207.434 512.823,209.008 518.562,260.514" fill="none" stroke="green" stroke-width="3" />
<text x="518.562195" y="260.513550" fill="green" font-size="12">48604</text>
<polyline points="735.211,254.415 786.412,252.762 780.482,204.829 728.771,205.129 735.211,254.415" fill="none" stroke="green" stroke-width="3" />
<text x="735.210571" y="254.415009" fill="green" font-size="12">48606</text>
<polyline points="641.713,356.746 695.351,354.275 689.092,304.539 635.63,306.659 641.713,356.746" fill="none" stroke="green" stroke-width="3" />
<text x="641.712585" y="356.745972" fill="green" font-size="12">48609</text>
<polyline points="847.957,344.39 895.766,342.601 889.634,295.359 841.706,296.65 847.957,344.39" fill="none" stroke="green" stroke-width="3" />
<text x="847.957031" y="344.389862" fill="green" font-size="12">48611</text>
<polyline points="541.065,468.426 599.424,463.54 593.043,411.102 535.536,415.271 541.065,468.426" fill="none" stroke="green" stroke-width="3" />
<text x="541.064819" y="468.426208" fill="green" font-size="12">48612</text>
<polyline points="759.733,450.327 812.033,445.965 805.214,396.167 753.646,400.271 759.733,450.327" fill="none" stroke="green" stroke-width="3" />
<text x="759.732910" y="450.327362" fill="green" font-size="12">48614</text>
<polyline points="665.526,561.614 720.573,555.544 714.737,504.023 659.297,509.377 665.526,561.614" fill="none" stroke="green" stroke-width="3" />
<text x="665.525635" y="561.614380" fill="green" font-size="12">48617</text>
<polyline points="873.2,539.353 923.237,534.105 916.228,484.7 866.586,489.291 873.2,539.353" fill="none" stroke="green" stroke-width="3" />
<text x="873.199768" y="539.352783" fill="green" font-size="12">48619</text>
<polyline points="508.57,161.554 566.257,161.075 560.64,109.519 502.976,109.487 508.57,161.554" fill="none" stroke="green" stroke-width="3" />
<text x="508.569702" y="161.553513" fill="green" font-size="12">48600</text>
<polyline points="723.971,159.44 776.209,159.77 769.577,110.807 717.985,110.36 723.971,159.44" fill="none" stroke="green" stroke-width="3" />
<text x="723.971497" y="159.439575" fill="green" font-size="12">48602</text>
<polyline points="680.18,207.697 624.8,208.208 631.001,259.087 685.843,257.849 680.18,207.697" fill="none" stroke="green" stroke-width="3" />
<text x="680.179504" y="207.696640" fill="green" font-size="12">48605</text>
<polyline points="835.555,251.462 884.879,251.209 878.427,202.746 829.21,203.881 835.555,251.462" fill="none" stroke="green" stroke-width="3" />
<text x="835.554993" y="251.461700" fill="green" font-size="12">48607</text>
<polyline points="531.402,365.236 588.602,361.786 581.787,310.172 524.964,312.933 531.402,365.236" fill="none" stroke="green" stroke-width="3" />
<text x="531.402344" y="365.235870" fill="green" font-size="12">48608</text>
<polyline points="749.381,353.553 799.943,350.367 793.67,301.761 742.782,304.533 749.381,353.553" fill="none" stroke="green" stroke-width="3" />
<text x="749.380554" y="353.552917" fill="green" font-size="12">48610</text>
<polyline points="704.556,405.732 649.145,409.02 654.927,461.28 711.184,457.207 704.556,405.732" fill="none" stroke="green" stroke-width="3" />
<text x="704.556458" y="405.732422" fill="green" font-size="12">48613</text>
<polyline points="860.786,443.784 911.163,440.626 903.89,391.646 854.757,393.964 860.786,443.784" fill="none" stroke="green" stroke-width="3" />
<text x="860.786133" y="443.784180" fill="green" font-size="12">48615</text>
<polyline points="553.941,575.834 612.32,569.507 606.886,516.176 547.775,522.218 553.941,575.834" fill="none" stroke="green" stroke-width="3" />
<text x="553.940918" y="575.834351" fill="green" font-size="12">48616</text>
<polyline points="773.32,551.863 825.849,545.706 819.72,494.74 766.975,500.167 773.32,551.863" fill="none" stroke="green" stroke-width="3" />
<text x="773.319641" y="551.862793" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 3.33980752481
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-9.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="331.796,179.575 398.035,189.569 395.757,129.765 330.483,118.607 331.796,179.575" fill="none" stroke="green" stroke-width="3" />
<text x="331.795715" y="179.574631" fill="green" font-size="12">48601</text>
<polyline points="569.365,215.626 621.879,224.079 623.512,171.88 570.107,161.631 569.365,215.626" fill="none" stroke="green" stroke-width="3" />
<text x="569.365417" y="215.626068" fill="green" font-size="12">48603</text>
<polyline points="198.914,282.412 268.121,288.495 267.338,229.509 195.165,221.004 198.914,282.412" fill="none" stroke="green" stroke-width="3" />
<text x="198.913910" y="282.412262" fill="green" font-size="12">48604</text>
<polyline points="457.602,306.475 514.791,312.369 514.794,260.056 457.519,252.764 457.602,306.475" fill="none" stroke="green" stroke-width="3" />
<text x="457.602051" y="306.474640" fill="green" font-size="12">48606</text>
<polyline points="338.808,404.953 400.323,407.798 398.998,355.028 336.651,350.535 338.808,404.953" fill="none" stroke="green" stroke-width="3" />
<text x="338.807770" y="404.953491" fill="green" font-size="12">48609</text>
<polyline points="566.986,416.086 617.135,418.671 617.892,371.553 567.347,367.559 566.986,416.086" fill="none" stroke="green" stroke-width="3" />
<text x="566.986328" y="416.086365" fill="green" font-size="12">48611</text>
<polyline points="212.856,511.161 280.776,510.973 278.63,457.284 209.694,456.002 212.856,511.161" fill="none" stroke="green" stroke-width="3" />
<text x="212.855713" y="511.161255" fill="green" font-size="12">48612</text>
<polyline points="459.367,509.293 514.244,509.179 514.504,461.733 459.173,460.669 459.367,509.293" fill="none" stroke="green" stroke-width="3" />
<text x="459.366730" y="509.293365" fill="green" font-size="12">48614</text>
<polyline points="345.979,609.103 405.024,605.901 403.759,558.341 344.48,560.164 345.979,609.103" fill="none" stroke="green" stroke-width="3" />
<text x="345.979401" y="609.102905" fill="green" font-size="12">48617</text>
<polyline points="563.161,597.582 610.9,594.896 611.962,552.58 564.201,553.876 563.161,597.582" fill="none" stroke="green" stroke-width="3" />
<text x="563.161377" y="597.582275" fill="green" font-size="12">48619</text>
<polyline points="189.934,153.998 264.651,164.868 262.333,100.89 186.154,87.7557 189.934,153.998" fill="none" stroke="green" stroke-width="3" />
<text x="189.934280" y="153.998489" fill="green" font-size="12">48600</text>
<polyline points="455.992,194.898 516.006,204.447 517.363,148.153 456.641,137.074 455.992,194.898" fill="none" stroke="green" stroke-width="3" />
<text x="455.991943" y="194.898392" fill="green" font-size="12">48602</text>
<polyline points="397.465,297.088 397.123,241.078 331.988,232.474 333.097,290.031 397.465,297.088" fill="none" stroke="green" stroke-width="3" />
<text x="397.465179" y="297.087921" fill="green" font-size="12">48605</text>
<polyline points="567.306,315.168 617.386,319.512 620.054,271.186 568.263,263.97 567.306,315.168" fill="none" stroke="green" stroke-width="3" />
<text x="567.305542" y="315.167755" fill="green" font-size="12">48607</text>
<polyline points="202.025,393.381 272.37,397.377 269.13,341.367 198.806,335.072 202.025,393.381" fill="none" stroke="green" stroke-width="3" />
<text x="202.024750" y="393.381042" fill="green" font-size="12">48608</text>
<polyline points="457.867,407.818 514.041,410.63 514.124,360.507 457.134,355.766 457.867,407.818" fill="none" stroke="green" stroke-width="3" />
<text x="457.866730" y="407.818268" fill="green" font-size="12">48610</text>
<polyline points="402.016,506.21 401.382,455.519 338.221,453.206 339.82,505.708 402.016,506.21" fill="none" stroke="green" stroke-width="3" />
<text x="402.015625" y="506.210236" fill="green" font-size="12">48613</text>
<polyline points="563.043,506.113 612.937,506.487 613.699,460.625 563.893,459.445 563.043,506.113" fill="none" stroke="green" stroke-width="3" />
<text x="563.043274" y="506.112549" fill="green" font-size="12">48615</text>
<polyline points="215.949,610.146 282.119,607.427 278.762,556.716 212.549,558.182 215.949,610.146" fill="none" stroke="green" stroke-width="3" />
<text x="215.949295" y="610.146484" fill="green" font-size="12">48616</text>
<polyline points="458.576,599.804 511.78,597.28 512.143,551.942 458.492,553.418 458.576,599.804" fill="none" stroke="green" stroke-width="3" />
<text x="458.575623" y="599.804138" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.30152949436
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-10.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="222.523,260.372 216.912,217.635 174.018,221.707 181.275,263.783 222.523,260.372" fill="none" stroke="green" stroke-width="3" />
<text x="222.522720" y="260.372314" fill="green" font-size="12">48601</text>
<polyline points="197.28,89.311 187.799,43.7878 145.962,47.1627 153.748,92.1406 197.28,89.311" fill="none" stroke="green" stroke-width="3" />
<text x="197.280319" y="89.311028" fill="green" font-size="12">48603</text>
<polyline points="317.014,337.112 311.372,295.127 269.805,298.668 276.05,340.646 317.014,337.112" fill="none" stroke="green" stroke-width="3" />
<text x="317.013885" y="337.112396" fill="green" font-size="12">48604</text>
<polyline points="295.508,169.239 289.733,124.955 245.201,128.285 251.416,172.433 295.508,169.239" fill="none" stroke="green" stroke-width="3" />
<text x="295.507935" y="169.239349" fill="green" font-size="12">48606</text>
<polyline points="389.96,246.367 384.329,203.367 341.378,206.95 347.696,249.611 389.96,246.367" fill="none" stroke="green" stroke-width="3" />
<text x="389.959595" y="246.366608" fill="green" font-size="12">48609</text>
<polyline points="366.48,74.5726 360.948,32.7228 317.286,34.8362 324.416,77.9818 366.48,74.5726" fill="none" stroke="green" stroke-width="3" />
<text x="366.480438" y="74.572601" fill="green" font-size="12">48611</text>
<polyline points="484.815,323.148 479.275,281.422 436.59,284.787 443.134,326.351 484.815,323.148" fill="none" stroke="green" stroke-width="3" />
<text x="484.815125" y="323.147705" fill="green" font-size="12">48612</text>
<polyline points="463.89,155.441 457.598,110.989 414.331,114.292 420.063,158.543 463.89,155.441" fill="none" stroke="green" stroke-width="3" />
<text x="463.889557" y="155.440750" fill="green" font-size="12">48614</text>
<polyline points="557.536,233.393 551.556,189.926 509.016,193.278 514.665,236.345 557.536,233.393" fill="none" stroke="green" stroke-width="3" />
<text x="557.535583" y="233.393188" fill="green" font-size="12">48617</text>
<polyline points="535.22,60.7091 529.013,17.2774 487.738,20.1942 492.589,64.0113 535.22,60.7091" fill="none" stroke="green" stroke-width="3" />
<text x="535.220459" y="60.709080" fill="green" font-size="12">48619</text>
<polyline points="209.138,172.819 202.463,127.248 158.11,131.195 165.383,176.04 209.138,172.819" fill="none" stroke="green" stroke-width="3" />
<text x="209.137878" y="172.819244" fill="green" font-size="12">48602</text>
<polyline points="261.948,254.224 304.561,250.986 299.075,207.864 256.2,211.195 261.948,254.224" fill="none" stroke="green" stroke-width="3" />
<text x="261.948456" y="254.223755" fill="green" font-size="12">48605</text>
<polyline points="280.276,78.5277 273.482,34.8403 230.918,37.4325 237.351,81.8099 280.276,78.5277" fill="none" stroke="green" stroke-width="3" />
<text x="280.276367" y="78.527657" fill="green" font-size="12">48607</text>
<polyline points="398.571,327.622 393.539,285.167 350.829,288.531 356.646,330.593 398.571,327.622" fill="none" stroke="green" stroke-width="3" />
<text x="398.570862" y="327.621948" fill="green" font-size="12">48608</text>
<polyline points="378.839,160.236 372.627,115.519 328.745,119.236 334.531,162.976 378.839,160.236" fill="none" stroke="green" stroke-width="3" />
<text x="378.838562" y="160.236038" fill="green" font-size="12">48610</text>
<polyline points="429.17,240.374 472.259,237.323 467.007,194.252 423.7,197.54 429.17,240.374" fill="none" stroke="green" stroke-width="3" />
<text x="429.169769" y="240.373611" fill="green" font-size="12">48613</text>
<polyline points="449.749,65.4532 443.392,21.9607 402.644,25.9096 406.869,68.6769 449.749,65.4532" fill="none" stroke="green" stroke-width="3" />
<text x="449.748932" y="65.453217" fill="green" font-size="12">48615</text>
<polyline points="565.843,314.411 560.579,272.552 518.264,275.53 524.113,317.545 565.843,314.411" fill="none" stroke="green" stroke-width="3" />
<text x="565.842590" y="314.410583" fill="green" font-size="12">48616</text>
<polyline points="545.751,146.685 538.839,101.83 496.324,105.396 501.664,149.68 545.751,146.685" fill="none" stroke="green" stroke-width="3" />
<text x="545.750671" y="146.685135" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.70201751052
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-11.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="109.224,440.647 102.671,390.23 35.9776,389.302 40.6165,440.269 109.224,440.647" fill="none" stroke="green" stroke-width="3" />
<text x="109.223740" y="440.646667" fill="green" font-size="12">48601</text>
<polyline points="89.1455,245.274 86.6879,196.433 16.7397,188.122 21.451,238.642 89.1455,245.274" fill="none" stroke="green" stroke-width="3" />
<text x="89.145515" y="245.273972" fill="green" font-size="12">48603</text>
<polyline points="237.444,532.384 232.67,485.309 172.758,486.599 177.778,534.575 237.444,532.384" fill="none" stroke="green" stroke-width="3" />
<text x="237.443558" y="532.384338" fill="green" font-size="12">48604</text>
<polyline points="216.631,347.064 212.562,302.017 154.301,297.594 158.851,344.357 216.631,347.064" fill="none" stroke="green" stroke-width="3" />
<text x="216.630951" y="347.064301" fill="green" font-size="12">48606</text>
<polyline points="337.795,439.96 330.585,395.771 277.674,394.691 282.245,439.68 337.795,439.96" fill="none" stroke="green" stroke-width="3" />
<text x="337.794800" y="439.960144" fill="green" font-size="12">48609</text>
<polyline points="315.488,266.903 311.849,224.639 259.014,217.852 263.363,262.02 315.488,266.903" fill="none" stroke="green" stroke-width="3" />
<text x="315.487518" y="266.903290" fill="green" font-size="12">48611</text>
<polyline points="444.487,522.683 439.544,480.798 390.689,481.531 395.723,524.38 444.487,522.683" fill="none" stroke="green" stroke-width="3" />
<text x="444.486633" y="522.683228" fill="green" font-size="12">48612</text>
<polyline points="424.254,357.528 418.145,316.254 370.656,312.942 375.639,354.946 424.254,357.528" fill="none" stroke="green" stroke-width="3" />
<text x="424.254028" y="357.527649" fill="green" font-size="12">48614</text>
<polyline points="524.131,440.143 518.483,400.44 474.786,399.468 479.742,439.829 524.131,440.143" fill="none" stroke="green" stroke-width="3" />
<text x="524.130798" y="440.142609" fill="green" font-size="12">48617</text>
<polyline points="503.282,284.007 498.349,245.13 454.578,240.281 459.621,279.853 503.282,284.007" fill="none" stroke="green" stroke-width="3" />
<text x="503.282379" y="284.006531" fill="green" font-size="12">48619</text>
<polyline points="113.413,536.891 108.2,486.684 41.2089,487.801 46.0645,539.5 113.413,536.891" fill="none" stroke="green" stroke-width="3" />
<text x="113.413376" y="536.890869" fill="green" font-size="12">48600</text>
<polyline points="161.438,390.917 165.37,439.293 226.656,439.598 220.325,392.921 161.438,390.917" fill="none" stroke="green" stroke-width="3" />
<text x="161.437576" y="390.916840" fill="green" font-size="12">48605</text>
<polyline points="207.906,256.612 204.111,210.875 143.436,203.321 148.534,250.846 207.906,256.612" fill="none" stroke="green" stroke-width="3" />
<text x="207.905884" y="256.611755" fill="green" font-size="12">48607</text>
<polyline points="344.03,528.151 338.21,483.178 283.31,483.638 288.533,530.062 344.03,528.151" fill="none" stroke="green" stroke-width="3" />
<text x="344.029724" y="528.150574" fill="green" font-size="12">48608</text>
<polyline points="325.236,353.673 320.333,310.113 267.727,306.292 271.578,350.06 325.236,353.673" fill="none" stroke="green" stroke-width="3" />
<text x="325.236298" y="353.672607" fill="green" font-size="12">48610</text>
<polyline points="379.694,397.919 383.775,440.47 433.692,441.264 428.466,399.601 379.694,397.919" fill="none" stroke="green" stroke-width="3" />
<text x="379.693573" y="397.918732" fill="green" font-size="12">48613</text>
<polyline points="414.263,276.515 410.385,236.083 362.791,231.432 366.332,272.093 414.263,276.515" fill="none" stroke="green" stroke-width="3" />
<text x="414.263428" y="276.515167" fill="green" font-size="12">48615</text>
<polyline points="532.209,521.014 527.509,481.012 482.64,481.267 487.556,522.566 532.209,521.014" fill="none" stroke="green" stroke-width="3" />
<text x="532.209351" y="521.014099" fill="green" font-size="12">48616</text>
<polyline points="513.143,363.443 506.917,323.424 463.47,320.164 468.795,360.542 513.143,363.443" fill="none" stroke="green" stroke-width="3" />
<text x="513.142700" y="363.443085" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.83027038725
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-12.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="449.389,528.154 414.49,532.364 415.015,578.261 449.636,574.586 449.389,528.154" fill="none" stroke="green" stroke-width="3" />
<text x="449.389191" y="528.153564" fill="green" font-size="12">48601</text>
<polyline points="318.298,545.141 285.711,548.773 287.065,591.858 318.288,588.834 318.298,545.141" fill="none" stroke="green" stroke-width="3" />
<text x="318.298492" y="545.140564" fill="green" font-size="12">48603</text>
<polyline points="519.482,422.83 481.858,429.777 483.058,476.621 519.695,471.04 519.482,422.83" fill="none" stroke="green" stroke-width="3" />
<text x="519.482239" y="422.830261" fill="green" font-size="12">48604</text>
<polyline points="381.949,447.838 349.403,453.597 349.204,497.17 381.573,492.473 381.949,447.838" fill="none" stroke="green" stroke-width="3" />
<text x="381.949127" y="447.837952" fill="green" font-size="12">48606</text>
<polyline points="445.61,345.667 411.475,352.892 412.795,397.474 446.471,390.547 445.61,345.667" fill="none" stroke="green" stroke-width="3" />
<text x="445.609863" y="345.667053" fill="green" font-size="12">48609</text>
<polyline points="316.837,373.322 289.007,380.853 288.867,422.391 316.957,416.265 316.837,373.322" fill="none" stroke="green" stroke-width="3" />
<text x="316.837280" y="373.322449" fill="green" font-size="12">48611</text>
<polyline points="513.637,237.215 477.862,246.604 479.161,291.914 514.729,282.953 513.637,237.215" fill="none" stroke="green" stroke-width="3" />
<text x="513.637085" y="237.214569" fill="green" font-size="12">48612</text>
<polyline points="379.272,273.819 347.61,282.036 347.336,323.899 379.685,316.917 379.272,273.819" fill="none" stroke="green" stroke-width="3" />
<text x="379.272125" y="273.819183" fill="green" font-size="12">48614</text>
<polyline points="445.219,168.574 411.057,178.722 411.071,222.259 444.655,212.678 445.219,168.574" fill="none" stroke="green" stroke-width="3" />
<text x="445.219391" y="168.574158" fill="green" font-size="12">48617</text>
<polyline points="319.947,208.123 291.098,217.633 290.435,258.082 318.112,249.028 319.947,208.123" fill="none" stroke="green" stroke-width="3" />
<text x="319.946808" y="208.123108" fill="green" font-size="12">48619</text>
<polyline points="520.16,516.529 482.062,521.703 482.69,569.466 521.101,565.677 520.16,516.529" fill="none" stroke="green" stroke-width="3" />
<text x="520.159790" y="516.529175" fill="green" font-size="12">48600</text>
<polyline points="378.363,535.925 345.495,539.721 345.66,584.986 378.31,580.68 378.363,535.925" fill="none" stroke="green" stroke-width="3" />
<text x="378.363037" y="535.925354" fill="green" font-size="12">48602</text>
<polyline points="411.418,485.898 447.39,480.926 447.015,433.877 411.215,440.614 411.418,485.898" fill="none" stroke="green" stroke-width="3" />
<text x="411.418060" y="485.897827" fill="green" font-size="12">48605</text>
<polyline points="315.152,456.268 284.45,461.874 283.119,504.58 315.379,500.74 315.152,456.268" fill="none" stroke="green" stroke-width="3" />
<text x="315.152313" y="456.267578" fill="green" font-size="12">48607</text>
<polyline points="515.25,326.969 479.144,336.377 479.984,382.217 516.885,374.439 515.25,326.969" fill="none" stroke="green" stroke-width="3" />
<text x="515.249817" y="326.969238" fill="green" font-size="12">48608</text>
<polyline points="378.053,358.908 345.932,365.576 346.316,409.457 378.004,402.934 378.053,358.908" fill="none" stroke="green" stroke-width="3" />
<text x="378.052521" y="358.907959" fill="green" font-size="12">48610</text>
<polyline points="409.84,307.328 444.107,299.49 443.746,254.414 409.587,263.626 409.84,307.328" fill="none" stroke="green" stroke-width="3" />
<text x="409.839600" y="307.328125" fill="green" font-size="12">48613</text>
<polyline points="513.789,145.979 477.289,157.132 477.219,201.516 513.863,191.889 513.789,145.979" fill="none" stroke="green" stroke-width="3" />
<text x="513.788574" y="145.978683" fill="green" font-size="12">48616</text>
<polyline points="379.252,187.789 346.92,197.151 346.528,238.513 378.183,230.733 379.252,187.789" fill="none" stroke="green" stroke-width="3" />
<text x="379.252136" y="187.789291" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 1.34260804628
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-13.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1052.53,157.188 1052.23,193.389 1095.32,193.191 1094.95,156.971 1052.53,157.188" fill="none" stroke="green" stroke-width="3" />
<text x="1052.528687" y="157.187790" fill="green" font-size="12">48601</text>
<polyline points="1052.21,305.428 1052.46,343.464 1096.25,343.87 1096.29,305.013 1052.21,305.428" fill="none" stroke="green" stroke-width="3" />
<text x="1052.206787" y="305.428101" fill="green" font-size="12">48603</text>
<polyline points="971.912,90.9223 970.733,125.06 1012.17,125.208 1012.15,89.8128 971.912,90.9223" fill="none" stroke="green" stroke-width="3" />
<text x="971.912415" y="90.922264" fill="green" font-size="12">48604</text>
<polyline points="967.488,230.942 966.609,267.274 1009.64,268.242 1010.37,231.057 967.488,230.942" fill="none" stroke="green" stroke-width="3" />
<text x="967.488159" y="230.941681" fill="green" font-size="12">48606</text>
<polyline points="887.061,157.464 885.002,193.691 927.278,194.286 928.883,157.873 887.061,157.464" fill="none" stroke="green" stroke-width="3" />
<text x="887.060913" y="157.463745" fill="green" font-size="12">48609</text>
<polyline points="878.816,303.766 877.17,343.88 920.487,344.197 922.152,303.888 878.816,303.766" fill="none" stroke="green" stroke-width="3" />
<text x="878.815857" y="303.766144" fill="green" font-size="12">48611</text>
<polyline points="810.125,86.6928 807.38,121.667 848.813,123.066 850.246,87.9601 810.125,86.6928" fill="none" stroke="green" stroke-width="3" />
<text x="810.125427" y="86.692841" fill="green" font-size="12">48612</text>
<polyline points="798.754,228.354 796.159,265.858 838.738,266.165 841.599,229.331 798.754,228.354" fill="none" stroke="green" stroke-width="3" />
<text x="798.753723" y="228.354401" fill="green" font-size="12">48614</text>
<polyline points="721.826,153.315 717.892,189.538 760.465,191.226 763.653,155.107 721.826,153.315" fill="none" stroke="green" stroke-width="3" />
<text x="721.825806" y="153.315475" fill="green" font-size="12">48617</text>
<polyline points="706.293,301.517 702.404,340.029 745.532,341.485 749.751,302.559 706.293,301.517" fill="none" stroke="green" stroke-width="3" />
<text x="706.293152" y="301.516876" fill="green" font-size="12">48619</text>
<polyline points="1053.5,88.3083 1053.45,123.143 1095.53,123.321 1094.5,87.8459 1053.5,88.3083" fill="none" stroke="green" stroke-width="3" />
<text x="1053.495850" y="88.308304" fill="green" font-size="12">48600</text>
<polyline points="1052.95,228.853 1053.2,266.806 1097.09,266.56 1096.56,228.912 1052.95,228.853" fill="none" stroke="green" stroke-width="3" />
<text x="1052.954712" y="228.852646" fill="green" font-size="12">48602</text>
<polyline points="970.637,157.803 969.213,195.071 1012.38,194.867 1013.17,157.97 970.637,157.803" fill="none" stroke="green" stroke-width="3" />
<text x="970.636841" y="157.802673" fill="green" font-size="12">48605</text>
<polyline points="966.161,303.23 965.944,343.331 1010.09,343.322 1010.21,303.838 966.161,303.23" fill="none" stroke="green" stroke-width="3" />
<text x="966.160828" y="303.230164" fill="green" font-size="12">48607</text>
<polyline points="891.915,88.7228 890.529,123.506 931.589,123.981 933.158,89.8362 891.915,88.7228" fill="none" stroke="green" stroke-width="3" />
<text x="891.915039" y="88.722786" fill="green" font-size="12">48608</text>
<polyline points="884.257,228.931 882.192,266.481 925.678,266.907 927.533,229.211 884.257,228.931" fill="none" stroke="green" stroke-width="3" />
<text x="884.256775" y="228.930695" fill="green" font-size="12">48610</text>
<polyline points="805.874,155.011 802.851,191.792 845.85,193.099 848.044,155.621 805.874,155.011" fill="none" stroke="green" stroke-width="3" />
<text x="805.874146" y="155.010681" fill="green" font-size="12">48613</text>
<polyline points="793.88,301.763 790.62,341.099 835.07,342.259 837.309,302.492 793.88,301.763" fill="none" stroke="green" stroke-width="3" />
<text x="793.880493" y="301.762512" fill="green" font-size="12">48615</text>
<polyline points="730.911,84.6644 727.124,119.45 768.819,120.577 771.829,85.5472 730.911,84.6644" fill="none" stroke="green" stroke-width="3" />
<text x="730.910706" y="84.664383" fill="green" font-size="12">48616</text>
<polyline points="715.602,225.177 711.426,262.848 755.006,263.613 758.854,226.392 715.602,225.177" fill="none" stroke="green" stroke-width="3" />
<text x="715.602051" y="225.177017" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 0.738898030151
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-14.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1553.72,133.092 1563.61,174.092 1613.6,157.766 1603.34,115.987 1553.72,133.092" fill="none" stroke="green" stroke-width="3" />
<text x="1553.724854" y="133.092209" fill="green" font-size="12">48601</text>
<polyline points="1593.31,295.632 1603.91,336.236 1654.12,323.394 1643.9,281.475 1593.31,295.632" fill="none" stroke="green" stroke-width="3" />
<text x="1593.311890" y="295.631622" fill="green" font-size="12">48603</text>
<polyline points="1445.19,90.0333 1453.12,128.696 1499.08,111.816 1489.56,72.2503 1445.19,90.0333" fill="none" stroke="green" stroke-width="3" />
<text x="1445.189575" y="90.033272" fill="green" font-size="12">48604</text>
<polyline points="1479.96,243.633 1489.17,282.961 1535.71,269.141 1526.81,228.814 1479.96,243.633" fill="none" stroke="green" stroke-width="3" />
<text x="1479.963989" y="243.632904" fill="green" font-size="12">48606</text>
<polyline points="1376.45,196.288 1384.53,234.247 1427.94,220.01 1419.45,181.131 1376.45,196.288" fill="none" stroke="green" stroke-width="3" />
<text x="1376.445190" y="196.288300" fill="green" font-size="12">48609</text>
<polyline points="1409.14,346.993 1417.65,385.809 1461.91,374.345 1452.72,334.926 1409.14,346.993" fill="none" stroke="green" stroke-width="3" />
<text x="1409.137939" y="346.993469" fill="green" font-size="12">48611</text>
<polyline points="1281.34,152.544 1288.94,189.175 1328.66,174.741 1320.71,137.811 1281.34,152.544" fill="none" stroke="green" stroke-width="3" />
<text x="1281.339722" y="152.543762" fill="green" font-size="12">48612</text>
<polyline points="1311.62,297.277 1319.5,333.456 1359.37,321.428 1351.73,284.654 1311.62,297.277" fill="none" stroke="green" stroke-width="3" />
<text x="1311.624146" y="297.276917" fill="green" font-size="12">48614</text>
<polyline points="1221.93,250.747 1228.88,285.993 1265.77,273.631 1258.83,237.938 1221.93,250.747" fill="none" stroke="green" stroke-width="3" />
<text x="1221.931274" y="250.747498" fill="green" font-size="12">48617</text>
<polyline points="1250.69,392.101 1257.74,428.166 1295.69,418.072 1288.29,381.367 1250.69,392.101" fill="none" stroke="green" stroke-width="3" />
<text x="1250.692993" y="392.101196" fill="green" font-size="12">48619</text>
<polyline points="1535.4,54.9133 1544.86,94.5622 1593.63,76.5964 1583.18,36.7477 1535.4,54.9133" fill="none" stroke="green" stroke-width="3" />
<text x="1535.401978" y="54.913307" fill="green" font-size="12">48600</text>
<polyline points="1572.68,213.413 1582.85,254.925 1633.83,239.938 1623.56,197.78 1572.68,213.413" fill="none" stroke="green" stroke-width="3" />
<text x="1572.679565" y="213.412918" fill="green" font-size="12">48602</text>
<polyline points="1469.94,206.516 1516.98,191.118 1507.94,150.146 1460.89,166.988 1469.94,206.516" fill="none" stroke="green" stroke-width="3" />
<text x="1469.938721" y="206.515533" fill="green" font-size="12">48605</text>
<polyline points="1498.98,321.366 1506.4,362.501 1555.1,348.82 1545.04,308.361 1498.98,321.366" fill="none" stroke="green" stroke-width="3" />
<text x="1498.980103" y="321.365814" fill="green" font-size="12">48607</text>
<polyline points="1359.45,122.671 1367.42,161.219 1410.52,145.492 1401.59,106.996 1359.45,122.671" fill="none" stroke="green" stroke-width="3" />
<text x="1359.451660" y="122.670517" fill="green" font-size="12">48608</text>
<polyline points="1391.82,272.122 1400.07,310.095 1443.51,297.098 1435.31,258.224 1391.82,272.122" fill="none" stroke="green" stroke-width="3" />
<text x="1391.823120" y="272.121887" fill="green" font-size="12">48610</text>
<polyline points="1303.32,261.778 1343.9,248.56 1336.25,210.368 1295.94,224.415 1303.32,261.778" fill="none" stroke="green" stroke-width="3" />
<text x="1303.319336" y="261.778351" fill="green" font-size="12">48613</text>
<polyline points="1326.47,370.716 1334.26,408.357 1375.25,397.868 1367.29,359.333 1326.47,370.716" fill="none" stroke="green" stroke-width="3" />
<text x="1326.474976" y="370.715607" fill="green" font-size="12">48615</text>
<polyline points="1207.62,180.704 1214.55,216.824 1252.01,203.147 1244.75,166.555 1207.62,180.704" fill="none" stroke="green" stroke-width="3" />
<text x="1207.622070" y="180.703964" fill="green" font-size="12">48616</text>
<polyline points="1236.03,321.214 1243.16,356.981 1280.84,346.027 1273.31,309.48 1236.03,321.214" fill="none" stroke="green" stroke-width="3" />
<text x="1236.033203" y="321.214142" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
<li style="padding-bottom: 1em">
RMSE 2.62738649114
<div style="position: relative; width: 300px; height: 168.75px">
<img style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px"
src="/calibration-poses/pose-1781543257841-15.jpeg">
<svg style="position: absolute; top: 0; left: 0; width: 300px; height: 168.75px; pointer-events: none"
viewBox="0 0 1920 1080">
<polyline points="1255.7,388.137 1251.02,445.53 1307.39,443.853 1312.76,386.928 1255.7,388.137" fill="none" stroke="green" stroke-width="3" />
<text x="1255.699829" y="388.136688" fill="green" font-size="12">48601</text>
<polyline points="1239.73,601.371 1236.68,651.07 1287.76,649.577 1292.41,600.228 1239.73,601.371" fill="none" stroke="green" stroke-width="3" />
<text x="1239.727051" y="601.371399" fill="green" font-size="12">48603</text>
<polyline points="1147.26,271.473 1145.18,332.074 1202.91,330.966 1206.82,270.446 1147.26,271.473" fill="none" stroke="green" stroke-width="3" />
<text x="1147.258789" y="271.473053" fill="green" font-size="12">48604</text>
<polyline points="1137.67,501.255 1135.62,553.909 1189.95,552.754 1193.53,499.673 1137.67,501.255" fill="none" stroke="green" stroke-width="3" />
<text x="1137.674683" y="501.254913" fill="green" font-size="12">48606</text>
<polyline points="1029.64,393.476 1029.01,450.736 1085.34,449.411 1086.36,392.575 1029.64,393.476" fill="none" stroke="green" stroke-width="3" />
<text x="1029.636353" y="393.476013" fill="green" font-size="12">48609</text>
<polyline points="1029.09,606.413 1028.92,654.209 1080.77,652.989 1082.07,605.387 1029.09,606.413" fill="none" stroke="green" stroke-width="3" />
<text x="1029.088501" y="606.413452" fill="green" font-size="12">48611</text>
<polyline points="911.075,276.23 913.477,337.422 971.42,335.891 970.828,275.242 911.075,276.23" fill="none" stroke="green" stroke-width="3" />
<text x="911.075012" y="276.230469" fill="green" font-size="12">48612</text>
<polyline points="919.15,506 921.341,559.042 976.094,557.775 975.237,504.786 919.15,506" fill="none" stroke="green" stroke-width="3" />
<text x="919.149841" y="505.999939" fill="green" font-size="12">48614</text>
<polyline points="800.865,398.154 804.965,455.395 862.443,455.207 858.716,397.235 800.865,398.154" fill="none" stroke="green" stroke-width="3" />
<text x="800.865417" y="398.153564" fill="green" font-size="12">48617</text>
<polyline points="817.13,611.343 820.856,659.969 873.256,658.937 870.209,610.112 817.13,611.343" fill="none" stroke="green" stroke-width="3" />
<text x="817.130249" y="611.342651" fill="green" font-size="12">48619</text>
<polyline points="1262.01,271.153 1257.41,331.515 1315.75,330.243 1321.73,269.976 1262.01,271.153" fill="none" stroke="green" stroke-width="3" />
<text x="1262.005249" y="271.153259" fill="green" font-size="12">48600</text>
<polyline points="1243.67,499.388 1239.41,552.76 1294.4,552.084 1299.76,498.953 1243.67,499.388" fill="none" stroke="green" stroke-width="3" />
<text x="1243.669922" y="499.388092" fill="green" font-size="12">48602</text>
<polyline points="1135.97,449.677 1193.04,449.324 1196.57,391.738 1139,392.404 1135.97,449.677" fill="none" stroke="green" stroke-width="3" />
<text x="1135.966187" y="449.677094" fill="green" font-size="12">48605</text>
<polyline points="1131.02,604.597 1127.74,654.367 1180.69,652.846 1184.05,603.718 1131.02,604.597" fill="none" stroke="green" stroke-width="3" />
<text x="1131.020508" y="604.596680" fill="green" font-size="12">48607</text>
<polyline points="1026.43,275.977 1026.09,337.427 1084.48,335.21 1086.13,275.842 1026.43,275.977" fill="none" stroke="green" stroke-width="3" />
<text x="1026.432983" y="275.976837" fill="green" font-size="12">48608</text>
<polyline points="1024.88,504.724 1024.79,557.832 1079.8,557.027 1081.06,503.469 1024.88,504.724" fill="none" stroke="green" stroke-width="3" />
<text x="1024.884399" y="504.723969" fill="green" font-size="12">48610</text>
<polyline points="913.945,453.659 971.481,453.367 970.403,394.959 912.237,395.764 913.945,453.659" fill="none" stroke="green" stroke-width="3" />
<text x="913.944580" y="453.659027" fill="green" font-size="12">48613</text>
<polyline points="919.647,609.295 920.405,659.233 972.941,657.444 972.74,608.38 919.647,609.295" fill="none" stroke="green" stroke-width="3" />
<text x="919.646973" y="609.295410" fill="green" font-size="12">48615</text>
<polyline points="789.46,276.95 793.62,339.281 853.132,339.043 849.148,276.958 789.46,276.95" fill="none" stroke="green" stroke-width="3" />
<text x="789.459595" y="276.949677" fill="green" font-size="12">48616</text>
<polyline points="806.015,508.322 809.568,561.605 864.443,561.062 862.566,507.445 806.015,508.322" fill="none" stroke="green" stroke-width="3" />
<text x="806.015076" y="508.322021" fill="green" font-size="12">48618</text>
</svg>
</div>
</li>
</ol>
<p>Calibration:</p><pre>
Camera intrinsics --------
width 1920
height 1080
fx 1013.037163
fy 1015.05071542
cx 986.505709454
cy 545.513675376
s 0.0
k1 0.0503748054324
k2 -0.0383457623661
p1 -0.0058226268105
p2 0.00403722808602
Camera RMSE 1.00882933419
Projector intrinsics -----
width 4096
height 2160
fx 5213.39604688
fy 5190.26370373
cx 1792.05592395
cy -83.5894167525
s 0.0
k1 -0.00229328944071
k2 -0.0183385876335
p1 0.00176316743657
p2 -0.0101564863249
Projector RMSE 0.549329201207
----
Stereo RMSE 1.13793057805
</pre>}
builtin-programs/gpu/enumerate.folk claims folk-sva has display monitor with info {name {monitor} phy (
[ m61851:1043 () ]
)builtin-programs/gpu/enumerate.folk claims folk-sva has display monitor with info {name {monitor} physicalDimensions {1016 571} physicalResolution {3840 2160} modes {{visibleRegion {3840 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 60000} {visibleRegion {4096 2160} refreshRate 59940} {visibleRegion {4096 2160} refreshRate 50000} {visibleRegion {4096 2160} refreshRate 30000} {visibleRegion {4096 2160} refreshRate 29970} {visibleRegion {4096 2160} refreshRate 25000} {visibleRegion {4096 2160} refreshRate 24000} {visibleRegion {4096 2160} refreshRate 23976} {visibleRegion {3840 2160} refreshRate 59940} {visibleRegion {3840 2160} refreshRate 50000} {visibleRegion {3840 2160} refreshRate 30000} {visibleRegion {3840 2160} refreshRate 29970} {visibleRegion {3840 2160} refreshRate 25000} {visibleRegion {3840 2160} refreshRate 24000} {visibleRegion {3840 2160} refreshRate 23976} {visibleRegion {2288 1430} refreshRate 61015} {visibleRegion {1920 1200} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 240000} {visibleRegion {1920 1080} refreshRate 120000} {visibleRegion {1920 1080} refreshRate 119880} {visibleRegion {1920 1080} refreshRate 60000} {visibleRegion {1920 1080} refreshRate 59940} {visibleRegion {1920 1080} refreshRate 50000} {visibleRegion {1920 1080} refreshRate 30000} {visibleRegion {1920 1080} refreshRate 29970} {visibleRegion {1920 1080} refreshRate 24000} {visibleRegion {1920 1080} refreshRate 23976} {visibleRegion {1600 1200} refreshRate 60000} {visibleRegion {1680 1050} refreshRate 60000} {visibleRegion {1280 1024} refreshRate 60000} {visibleRegion {1440 900} refreshRate 60000} {visibleRegion {1280 800} refreshRate 60000} {visibleRegion {1280 720} refreshRate 60000} {visibleRegion {1280 720} refreshRate 59940} {visibleRegion {1280 720} refreshRate 50000} {visibleRegion {1024 768} refreshRate 60000} {visibleRegion {800 600} refreshRate 60000} {visibleRegion {720 576} refreshRate 50000} {visibleRegion {720 480} refreshRate 60000} {visibleRegion {720 480} refreshRate 59940} {visibleRegion {640 480} refreshRate 60000} {visibleRegion {640 480} refreshRate 59940}}}
builtin-programs/gpu/enumerate.folk claims folk-sva has had displays enumerated (
[ m1096:0 (s1890:0 s1891:0) ]
)builtin-programs/gpu/enumerate.folk claims folk-sva has had displays enumerated
builtin-programs/tags-to-quads.folk claims the pose library is <C:cfile03l1Md> (
[ m1393:0 (s2255:0) ]
[ m1394:0 (s2258:0) ]
[ m1396:0 (s2260:0) ]
[ m1399:0 (s2263:0) ]
[ m60960:855 () ]
[ m60151:887 () ]
[ m6536:944 (s53061:1173) ]
)builtin-programs/tags-to-quads.folk claims the pose library is <C:cfile03l1Md>
builtin-programs/tags-to-quads.folk claims the changer from space /dev/v4l/by-path/pci-0000:03:00.4-u (
[ m1402:0 () ]
)builtin-programs/tags-to-quads.folk claims the changer from space /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 to space {display monitor} is {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}
builtin-programs/tags-to-quads.folk claims the changer from space {display monitor} to space /dev/v4l (
[ m1403:0 () ]
)builtin-programs/tags-to-quads.folk claims the changer from space {display monitor} to space /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 is {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}
builtin-programs/tags-to-quads.folk claims the quad library is <library:/tmp/quadLib_K8EENR.tcl> (
[ m1391:0 (s2252:0) ]
[ m1392:0 (s2254:0) ]
[ m1395:0 (s2257:0) ]
[ m1397:0 (s2261:0) ]
[ m1398:0 (s2262:0) ]
[ m6525:944 (s53047:1174) ]
[ m6529:989 (s53049:1174) ]
[ m6540:943 (s53066:1173) ]
)builtin-programs/tags-to-quads.folk claims the quad library is <library:/tmp/quadLib_K8EENR.tcl>
builtin-programs/tags-to-quads.folk claims the quad changer is {apply \{fn\ envStack\ args\}\ \{\n\ \ (
[ m1406:0 (s2269:0) ]
[ m1407:0 (s2271:0) ]
[ m1408:0 (s2270:0) ]
[ m1409:0 (s2272:0) ]
[ m1410:0 (s2273:0) ]
[ m60963:855 () ]
[ m60154:882 () ]
[ m6543:990 (s53070:1171) ]
)builtin-programs/tags-to-quads.folk claims the quad changer is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} {{this builtin-programs/tags-to-quads.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} poseLib <C:cfile03l1Md> cc ::<reference.<C______>.00000000000000000002>} {quadLib <library:/tmp/quadLib_K8EENR.tcl>} {} {results {{sourceSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 targetSpace {display monitor} changer {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}} {changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}} sourceSpace {display monitor} ^quadChange {{q targetSpace} \n\ \ \ \ \ \ \ \ package\ require\ linalg\n\ \ \ \ \ \ \ \ namespace\ import\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::add\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::sub\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ ::math::linearalgebra::matmul\n\n\ \ \ \ \ \ \ \ set\ sourceSpace\ \[\$quadLib\ space\ \$q\]\n\ \ \ \ \ \ \ \ if\ \{\$sourceSpace\ eq\ \$targetSpace\}\ \{\ return\ \$q\ \}\n\n\ \ \ \ \ \ \ \ set\ changer\ \[dict\ get\ \$changers\ \$sourceSpace\ \$targetSpace\]\n\ \ \ \ \ \ \ \ \$quadLib\ create\ \$targetSpace\ \[lmap\ v\ \[\$quadLib\ vertices\ \$q\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$changer\ \$v\n\ \ \ \ \ \ \ \ \}\]\n\ \ \ \ {builtin-programs/tags-to-quads.folk 372}} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changers {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{display monitor} {apply {{R t v} {
add [matmul $R $v] $t
}} {{-0.999504538768 0.0264305661162 0.0170909963538} {-0.0199308745711 -0.95174277262 0.306249008168} {0.024360566915 0.305756635153 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}} {display monitor} {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}} result {sourceSpace {display monitor} targetSpace /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 changer {apply {{Rt t v} {
add [matmul $Rt [sub $v $t]] $v
}} {{-0.999504538768 -0.0199308745711 0.024360566915} {0.0264305661162 -0.95174277262 0.305756635153} {0.0170909963538 0.306249008168 0.951798005274}} {0.00950987780512 0.0157209796983 0.70557852591}}}}}}
builtin-programs/tags-to-quads.folk claims tag 54 is stabilized with state {frozen 1 frozenPose {R {{ ()builtin-programs/tags-to-quads.folk claims tag 54 is stabilized with state {frozen 1 frozenPose {R {{0.096692973895 0.879075545404 -0.466772593705} {-0.900724824396 -0.122255375215 -0.41683139748} {-0.423491746791 0.460738329909 0.779983930484}} t {-0.19941389107 -0.120591044524 0.674286641286}} unfreezeTime 1781629980.63}
builtin-programs/tags-to-quads.folk wishes the GPU draws pipeline image with arguments {{4096 2160} { ()builtin-programs/tags-to-quads.folk wishes the GPU draws pipeline image with arguments {{4096 2160} {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} 12 {2819.85043583 692.200486425} {2822.41934385 1411.2377968} {2298.53328421 1478.99103869} {2347.71469379 780.809888049}} layer 0
builtin-programs/tags-to-quads.folk wishes the GPU draws pipeline image with arguments {{4096 2160} { ()builtin-programs/tags-to-quads.folk wishes the GPU draws pipeline image with arguments {{4096 2160} {{0.00048828125 0 -1} {0 0.000925925925926 -1} {0 0 1}} 10 {2850.02978188 1448.01961277} {2851.93561449 1878.06068517} {2565.75972276 1904.26788278} {2579.89685971 1482.10978542}} layer 0
builtin-programs/tags-to-quads.folk wishes 11 has resolved geometry (
[ m25654:915 (s2781:1088) ]
)builtin-programs/tags-to-quads.folk wishes 11 has resolved geometry
builtin-programs/tags-to-quads.folk wishes 82 has resolved geometry (
[ m6390:990 (s52871:1153) ]
)builtin-programs/tags-to-quads.folk wishes 82 has resolved geometry
builtin-programs/tags-to-quads.folk wishes 62 has resolved geometry (
[ m3057:1024 (s31837:1157) ]
)builtin-programs/tags-to-quads.folk wishes 62 has resolved geometry
builtin-programs/tags-to-quads.folk wishes 63 has resolved geometry (
[ m44637:1039 (s51832:1233) ]
)builtin-programs/tags-to-quads.folk wishes 63 has resolved geometry
builtin-programs/tags-to-quads.folk wishes 54 has resolved geometry (
[ m23346:1061 (s14672:1259) ]
)builtin-programs/tags-to-quads.folk wishes 54 has resolved geometry
builtin-programs/tags-to-quads.folk wishes 83 has resolved geometry (
[ m47700:1059 (s64449:987) ]
)builtin-programs/tags-to-quads.folk wishes 83 has resolved geometry
builtin-programs/draw/text.folk wishes the GPU compiles function glyphMsd {
{sampler2D atlas vec4 (
[ m23455:0 (s30992:0) ]
)builtin-programs/draw/text.folk wishes the GPU compiles function glyphMsd {
{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));
}
}
builtin-programs/draw/text.folk wishes the GPU compiles function median {
{float r float g float (
[ m23466:0 (s31006:0) ]
)builtin-programs/draw/text.folk wishes the GPU compiles function median {
{float r float g float b} float {
return max(min(r, g), min(max(r, g), b));
}
}
builtin-programs/draw/text.folk wishes the GPU compiles pipeline glyph {
{mat3 surfaceToClip
(
[ m23548:0 (s37502:0) ]
)builtin-programs/draw/text.folk wishes the GPU compiles pipeline glyph {
{mat3 surfaceToClip
vec4 atlasGlyphBounds
vec4 color
vec2 viewport
vec2 a vec2 b vec2 c vec2 d
sampler2D atlas
fn rotate} {
vec2 vertices[6] = vec2[6](a, b, c, a, c, d);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {fn rotate fn invBilinear fn glyphMsd fn median} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
vec2 glyphUv = invBilinear(surfaceXy.xy, a, b, c, d);
if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) {
return vec4(0.0);
}
vec3 msd = glyphMsd(atlas, atlasGlyphBounds, glyphUv).rgb;
// https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817
float sd = median(msd.r, msd.g, msd.b);
float uBuffer = 0.2;
float uGamma = 0.2;
float opacity = smoothstep(uBuffer - uGamma, uBuffer + uGamma, sd);
return (opacity < 0.01) ? vec4(0.0) : vec4(color.rgb, opacity * color.a);
}}
builtin-programs/draw/text.folk wishes the GPU loads image {width {208} height {208} components {3} b (
[ m18006:0 (s23875:0) ]
)builtin-programs/draw/text.folk wishes the GPU loads image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c298ac0}} as texture
builtin-programs/draw/text.folk wishes the GPU loads image {width {200} height {200} components {3} b (
[ m18007:0 (s23874:0) ]
)builtin-programs/draw/text.folk wishes the GPU loads image {width {200} height {200} components {3} bytesPerRow {600} uniq {0} data {(uint8_t*) 0x79d17c2f4430}} as texture
builtin-programs/draw/text.folk wishes the GPU loads image {width {192} height {192} components {3} b (
[ m18008:0 (s23873:0) ]
)builtin-programs/draw/text.folk wishes the GPU loads image {width {192} height {192} components {3} bytesPerRow {576} uniq {0} data {(uint8_t*) 0x79d17c42a090}} as texture
builtin-programs/draw/text.folk wishes the GPU loads image {width {208} height {208} components {3} b (
[ m18003:0 (s23872:0) ]
)builtin-programs/draw/text.folk wishes the GPU loads image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c466c40}} as texture
builtin-programs/draw/text.folk wishes the GPU draws pipeline glyph onto canvas {monitor canvas} with (
[ m51794:1062 () ]
)builtin-programs/draw/text.folk wishes the GPU draws pipeline glyph onto canvas {monitor canvas} with instances {{{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.0025 0.8375 0.0475 0.9975} {1.0 1.0 1.0 1.0} {4096 2160} {2922.07 747.579} {2922.11 757.704} {2886.11 757.833} {2886.07 747.708} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.2525 0.0625 0.3325 0.1575} {1.0 1.0 1.0 1.0} {4096 2160} {2914.94 756.807} {2915 774.807} {2893.63 774.884} {2893.56 756.884} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1975 0.1625 0.2775 0.2875} {1.0 1.0 1.0 1.0} {4096 2160} {2921.76 775.287} {2921.83 793.287} {2893.7 793.387} {2893.64 775.388} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.6475 0.2925 0.6775 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2922.2 795.725} {2922.22 802.475} {2894.1 802.575} {2894.07 795.825} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.5225 0.1725 0.5875 0.2875} {1.0 1.0 1.0 1.0} {4096 2160} {2919.33 802.741} {2919.38 817.366} {2893.51 817.459} {2893.46 802.834} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.2525 0.0625 0.3325 0.1575} {1.0 1.0 1.0 1.0} {4096 2160} {2915.15 816.315} {2915.21 834.315} {2893.84 834.391} {2893.78 816.391} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1975 0.1625 0.2775 0.2875} {1.0 1.0 1.0 1.0} {4096 2160} {2921.98 834.795} {2922.04 852.795} {2893.92 852.895} {2893.85 834.895} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.6825 0.2925 0.7575 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2922.3 864.894} {2922.36 881.769} {2894.23 881.87} {2894.17 864.995} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.9425 0.3225 0.9975 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2915.57 883.188} {2915.61 895.563} {2894.24 895.64} {2894.19 883.265} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.6475 0.2925 0.6775 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2922.55 895.696} {2922.58 902.446} {2894.45 902.547} {2894.43 895.797} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.2275 0.0075 0.2625 0.0575} {1.0 1.0 1.0 1.0} {4096 2160} {2900.47 903.978} {2900.49 911.853} {2889.24 911.894} {2889.22 904.019} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1575 0.7025 0.2425 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.07 921.871} {2923.13 940.996} {2893.88 941.1} {2893.82 921.975} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.3325 0.7025 0.4125 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.14 942.053} {2923.2 960.053} {2893.95 960.158} {2893.89 942.158} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1675 0.2925 0.2775 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2922.68 972.34} {2922.77 997.09} {2894.65 997.19} {2894.56 972.441} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.7225 0.1925 0.7975 0.2875} {1.0 1.0 1.0 1.0} {4096 2160} {2915.8 998.982} {2915.86 1015.86} {2894.49 1015.93} {2894.43 999.059} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.8025 0.5575 0.8875 0.6825} {1.0 1.0 1.0 1.0} {4096 2160} {2915.55 1015.71} {2915.62 1034.84} {2887.49 1034.94} {2887.42 1015.81} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.6425 0.5575 0.7175 0.6825} {1.0 1.0 1.0 1.0} {4096 2160} {2923.16 1044.15} {2923.22 1061.03} {2895.09 1061.13} {2895.03 1044.25} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1575 0.7025 0.2425 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.57 1063.06} {2923.64 1082.19} {2894.39 1082.29} {2894.32 1063.17} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.6425 0.5575 0.7175 0.6825} {1.0 1.0 1.0 1.0} {4096 2160} {2923.3 1083.39} {2923.36 1100.27} {2895.23 1100.37} {2895.17 1083.49} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.2475 0.7025 0.3275 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.71 1102.99} {2923.78 1120.99} {2894.53 1121.09} {2894.46 1103.09} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.2275 0.0075 0.2625 0.0575} {1.0 1.0 1.0 1.0} {4096 2160} {2901.24 1121.74} {2901.27 1129.62} {2890.02 1129.66} {2889.99 1121.78} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1575 0.7025 0.2425 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.84 1139.63} {2923.91 1158.76} {2894.66 1158.86} {2894.59 1139.74} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.4175 0.7025 0.4975 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2923.91 1159.67} {2923.98 1177.67} {2894.73 1177.78} {2894.66 1159.78} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.4275 0.0625 0.4575 0.1575} {1.0 1.0 1.0 1.0} {4096 2160} {2916.36 1180.64} {2916.39 1187.39} {2895.01 1187.47} {2894.99 1180.72} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1575 0.7025 0.2425 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2924.01 1186.76} {2924.08 1205.88} {2894.83 1205.99} {2894.76 1186.86} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1575 0.7025 0.2425 0.8325} {1.0 1.0 1.0 1.0} {4096 2160} {2924.08 1206.38} {2924.15 1225.5} {2894.9 1225.61} {2894.83 1206.48} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.0025 0.2925 0.0825 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2923.77 1237.29} {2923.84 1255.29} {2895.71 1255.39} {2895.65 1237.39} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.1675 0.2925 0.2775 0.4175} {1.0 1.0 1.0 1.0} {4096 2160} {2923.7 1257.35} {2923.79 1282.1} {2895.66 1282.2} {2895.58 1257.45} 3} {{{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} {0.0525 0.8375 0.0975 0.9975} {1.0 1.0 1.0 1.0} {4096 2160} {2923.99 1282.9} {2924.02 1293.02} {2888.02 1293.15} {2887.99 1283.02} 3}} layer 0
builtin-programs/draw/text.folk wishes the GPU draws pipeline glyph onto canvas {54 canvas} with inst ()builtin-programs/draw/text.folk wishes the GPU draws pipeline glyph onto canvas {54 canvas} with instances {{{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.6825 0.2925 0.7575 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0799425 0.0846875} {0.0893175 0.0846875} {0.0893175 0.100313} {0.0799425 0.100313} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.0025 0.2925 0.0825 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.09053 0.0846075} {0.10053 0.0846075} {0.10053 0.100232} {0.09053 0.100232} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.1975 0.5525 0.2825 0.6825} {1.0 1.0 1.0 1.0} {1024 1024} {0.100627 0.084375} {0.111253 0.084375} {0.111253 0.100625} {0.100627 0.100625} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.4275 0.0625 0.4575 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.112365 0.0886125} {0.116115 0.0886125} {0.116115 0.100488} {0.112365 0.100488} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.8375 0.4225 0.9325 0.5475} {1.0 1.0 1.0 1.0} {1024 1024} {0.120482 0.0845775} {0.132357 0.0845775} {0.132357 0.100203} {0.120482 0.100203} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.6825 0.2925 0.7575 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0424925 0.104687} {0.0518675 0.104687} {0.0518675 0.120312} {0.0424925 0.120312} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.9425 0.3225 0.9975 0.4175} {1.0 1.0 1.0 1.0} {1024 1024} {0.0526425 0.108462} {0.0595175 0.108462} {0.0595175 0.120337} {0.0526425 0.120337} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.7225 0.1925 0.7975 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.0588125 0.108562} {0.0681875 0.108562} {0.0681875 0.120437} {0.0588125 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.8025 0.1925 0.9225 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.06943 0.108443} {0.08443 0.108443} {0.08443 0.120317} {0.06943 0.120317} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.2525 0.0625 0.3325 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.08505 0.108562} {0.09505 0.108562} {0.09505 0.120437} {0.08505 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.9275 0.1925 0.9975 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.100765 0.108562} {0.109515 0.108562} {0.109515 0.120437} {0.100765 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.3375 0.0625 0.4225 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.109537 0.108562} {0.120162 0.108562} {0.120162 0.120437} {0.109537 0.120437} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.1725 0.0625 0.2475 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.120942 0.108682} {0.130317 0.108682} {0.130317 0.120557} {0.120942 0.120557} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.0025 0.0625 0.0775 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.131852 0.108443} {0.141227 0.108443} {0.141227 0.120317} {0.131852 0.120317} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.5225 0.1725 0.5875 0.2875} {1.0 1.0 1.0 1.0} {1024 1024} {0.141257 0.106212} {0.149382 0.106212} {0.149382 0.120587} {0.141257 0.120587} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.4275 0.0625 0.4575 0.1575} {1.0 1.0 1.0 1.0} {1024 1024} {0.149815 0.108612} {0.153565 0.108612} {0.153565 0.120487} {0.149815 0.120487} 3} {{{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}} {0.2475 0.7025 0.3275 0.8325} {1.0 1.0 1.0 1.0} {1024 1024} {0.15895 0.104375} {0.16895 0.104375} {0.16895 0.120625} {0.15895 0.120625} 3}} layer 0
builtin-programs/draw/text.folk claims the GPU has font CourierPrimeCode with data {(Font*) 0x79d1bc4 ()builtin-programs/draw/text.folk claims the GPU has font CourierPrimeCode with data {(Font*) 0x79d1bc4d0990}
builtin-programs/draw/text.folk claims the GPU has font PTSans-Regular with data {(Font*) 0x79d1a05e7 (
[ m51789:1065 (s16246:1264) ]
[ m31726:1066 () ]
[ m32023:1065 () ]
[ m32117:1067 () ]
[ m32166:1067 () ]
[ m32189:948 () ]
[ m32210:1067 () ]
[ m32232:1067 () ]
[ m32249:1067 () ]
[ m32303:1061 () ]
[ m32354:1067 (s15072:1259) ]
[ m32417:1040 () ]
[ m32433:1067 (s15176:1260) ]
[ m32482:1040 () ]
[ m32505:1040 (s15250:1266) ]
[ m32535:1066 (s15280:1262) ]
)builtin-programs/draw/text.folk claims the GPU has font PTSans-Regular with data {(Font*) 0x79d1a05e75b0}
builtin-programs/draw/text.folk claims the GPU has font NeomatrixCode with data {(Font*) 0x79d1c430c3 ()builtin-programs/draw/text.folk claims the GPU has font NeomatrixCode with data {(Font*) 0x79d1c430c300}
builtin-programs/draw/text.folk claims the GPU has font VictorMonoRegular with data {(Font*) 0x79d194 ()builtin-programs/draw/text.folk claims the GPU has font VictorMonoRegular with data {(Font*) 0x79d19465fdd0}
builtin-programs/camera/usb.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video- (
[ m1675:0 (s2610:0) ]
[ m1676:0 (s2608:0) ]
[ m1677:0 (s2607:0 s2609:0) ]
)builtin-programs/camera/usb.folk claims camera /dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 has width 1920 height 1080
builtin-programs/programs.folk claims tag 62 has a program (
[ m47938:640 (s15542:766 s15543:765) ]
[ m48150:643 () ]
)builtin-programs/programs.folk claims tag 62 has a program
builtin-programs/programs.folk claims tag 62 is a tag ()builtin-programs/programs.folk claims tag 62 is a tag
builtin-programs/programs.folk claims tag 11 has a program (
[ m33923:727 (s14332:865 s14334:865) ]
[ m33949:727 () ]
)builtin-programs/programs.folk claims tag 11 has a program
builtin-programs/programs.folk claims tag 11 is a tag ()builtin-programs/programs.folk claims tag 11 is a tag
builtin-programs/programs.folk claims tag 54 has a program (
[ m6500:990 (s53011:1175 s53015:1174) ]
[ m6520:986 () ]
)builtin-programs/programs.folk claims tag 54 has a program
builtin-programs/programs.folk claims tag 54 is a tag ()builtin-programs/programs.folk claims tag 54 is a tag
builtin-programs/programs.folk claims tag 82 has a program (
[ m6661:984 (s53207:1171 s53209:1174 s53210:1174) ]
[ m6714:990 () ]
)builtin-programs/programs.folk claims tag 82 has a program
builtin-programs/programs.folk claims tag 82 is a tag ()builtin-programs/programs.folk claims tag 82 is a tag
builtin-programs/programs.folk claims tag 63 has a program (
[ m3369:1022 (s32219:1211 s32220:1215) ]
[ m3413:1024 () ]
)builtin-programs/programs.folk claims tag 63 has a program
builtin-programs/programs.folk claims tag 63 is a tag ()builtin-programs/programs.folk claims tag 63 is a tag
builtin-programs/programs.folk claims tag 83 has a program (
[ m47701:1059 (s64455:1262 s64457:987 s64460:1258) ]
[ m47704:1063 () ]
)builtin-programs/programs.folk claims tag 83 has a program
builtin-programs/programs.folk claims tag 83 is a tag ()builtin-programs/programs.folk claims tag 83 is a tag
builtin-programs/tags-geometry.folk claims 11 has resolved geometry {tagSize 0.03 left 0.151 right 0. (
[ m25738:915 (s2881:1088) ]
[ m25744:915 (s2886:1087) ]
[ m25747:915 () ]
[ m25749:914 (s2891:1084) ]
[ m25752:915 (s2895:1084) ]
[ m29217:1067 () ]
[ m31105:1064 () ]
[ m31161:1067 () ]
[ m31431:1065 () ]
[ m31557:1067 () ]
[ m31730:1067 () ]
[ m31976:1067 (s14548:1265) ]
[ m32022:1065 () ]
[ m32248:1066 () ]
[ m32277:1066 () ]
[ m32444:1067 (s15188:1260) ]
)builtin-programs/tags-geometry.folk claims 11 has resolved geometry {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}
builtin-programs/tags-geometry.folk claims 11 has canvas projection {{9.47867298578 0 -1} {0 14.38848 (
[ m25672:915 (s2806:1088) ]
[ m25687:915 (s2822:1087) ]
[ m25692:912 (s2829:1086) ]
[ m25698:911 (s2835:1088) ]
[ m24440:1057 () ]
[ m27131:1066 () ]
[ m29224:1067 () ]
[ m31985:1067 (s14554:1262 s14555:1258) ]
)builtin-programs/tags-geometry.folk claims 11 has canvas projection {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 11 has canvas {11 canvas} with width 1024 height 1024 sett (
[ m25667:915 (s2802:1088) ]
[ m25670:912 (s2804:1088) ]
[ m25674:915 (s2820:1088) ]
[ m25689:915 (s2826:1086) ]
[ m25697:914 (s2833:1077) ]
[ m29222:1066 () ]
[ m31984:1067 (s14552:1265) ]
)builtin-programs/tags-geometry.folk claims 11 has canvas {11 canvas} with width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}
builtin-programs/tags-geometry.folk claims 82 has resolved geometry {tagSize 0.023 left 0.1697 right (
[ m6744:990 (s53309:1175) ]
[ m6747:978 (s53312:1172) ]
[ m47736:1064 (s64501:1262) ]
[ m32545:1067 (s15294:1251) ]
)builtin-programs/tags-geometry.folk claims 82 has resolved geometry {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}
builtin-programs/tags-geometry.folk claims 82 has canvas projection {{9.26354793886 0 -1} {0 14.31639 (
[ m6725:990 (s53286:1175) ]
[ m6731:990 (s53294:1175) ]
[ m6737:978 (s53301:1172) ]
[ m6740:990 (s53302:1175) ]
[ m6743:978 (s53305:1175) ]
[ m32477:1066 () ]
[ m32533:1067 (s15279:1251) ]
)builtin-programs/tags-geometry.folk claims 82 has canvas projection {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 82 has canvas {82 canvas} with width 1024 height 1024 sett (
[ m6673:985 (s53228:1173) ]
[ m6722:990 (s53281:1175) ]
[ m6728:990 (s53291:1175) ]
[ m6735:989 (s53297:1175) ]
[ m6736:978 (s53300:1175) ]
[ m6741:979 (s53303:1172) ]
[ m32531:1067 (s15277:1264) ]
)builtin-programs/tags-geometry.folk claims 82 has canvas {82 canvas} with width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}
builtin-programs/tags-geometry.folk claims 62 has resolved geometry {tagSize 0.03 left 0.151 right 0. (
[ m3084:1024 (s31877:1215) ]
[ m3087:1024 (s31879:1214) ]
[ m31284:1067 () ]
[ m31601:1060 () ]
[ m31896:1067 () ]
[ m32139:1067 () ]
[ m32287:1067 () ]
[ m32343:1067 () ]
)builtin-programs/tags-geometry.folk claims 62 has resolved geometry {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}
builtin-programs/tags-geometry.folk claims 62 has canvas projection {{9.47867298578 0 -1} {0 14.38848 (
[ m3072:1023 (s31859:1214) ]
[ m3075:1024 (s31866:1215) ]
[ m3079:1024 (s31869:1203) ]
[ m3081:1024 (s31874:1215) ]
)builtin-programs/tags-geometry.folk claims 62 has canvas projection {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 62 has canvas {62 canvas} with width 1024 height 1024 sett (
[ m3062:1023 (s31851:1214) ]
[ m3068:1024 (s31855:1214) ]
[ m3073:1003 (s31863:1214) ]
[ m3077:1024 (s31868:1203) ]
[ m3080:1024 (s31871:1202) ]
)builtin-programs/tags-geometry.folk claims 62 has canvas {62 canvas} with width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}
builtin-programs/tags-geometry.folk claims 63 has resolved geometry {tagSize 0.03 left 0.151 right 0. (
[ m44677:1037 (s51878:1228) ]
[ m44680:1038 (s51881:1224) ]
[ m31278:1066 () ]
[ m31286:1067 () ]
[ m31736:1066 () ]
[ m31764:1067 () ]
[ m31769:1066 () ]
[ m31964:1067 () ]
[ m31970:1067 () ]
[ m32058:1066 () ]
[ m32084:1066 () ]
[ m32089:1067 () ]
[ m32398:1067 () ]
[ m32422:1040 () ]
[ m32428:1067 (s15173:1263) ]
)builtin-programs/tags-geometry.folk claims 63 has resolved geometry {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}
builtin-programs/tags-geometry.folk claims 63 has canvas projection {{9.47867298578 0 -1} {0 14.38848 (
[ m44658:1033 (s51860:1230) ]
[ m44664:1039 (s51863:1228) ]
[ m44668:1038 (s51868:1213) ]
[ m44675:1039 (s51875:1233) ]
[ m31981:1066 () ]
[ m32106:1067 () ]
[ m32436:1067 (s15180:1266 s15182:1260) ]
)builtin-programs/tags-geometry.folk claims 63 has canvas projection {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 63 has canvas {63 canvas} with width 1024 height 1024 sett (
[ m44647:1033 (s51855:1233) ]
[ m44655:1032 (s51857:1233) ]
[ m44662:1033 (s51862:1213) ]
[ m44666:1039 (s51865:1231) ]
[ m44670:1033 (s51873:1209) ]
[ m31980:1067 () ]
[ m32104:1067 () ]
[ m32434:1039 (s15177:1264) ]
)builtin-programs/tags-geometry.folk claims 63 has canvas {63 canvas} with width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}
builtin-programs/tags-geometry.folk claims 54 has resolved geometry {tagSize 0.03 left 0.151 right 0. (
[ m23371:1040 (s14702:1260) ]
[ m23375:1039 (s14707:1259) ]
[ m23434:1062 (s14780:1223) ]
[ m23479:1060 (s14832:1244) ]
[ m32057:1067 () ]
[ m32335:1067 () ]
[ m32541:1067 (s15291:1263) ]
)builtin-programs/tags-geometry.folk claims 54 has resolved geometry {tagSize 0.03 left 0.151 right 0.03 top 0.03 bottom 0.079 width 0.211 height 0.139}
builtin-programs/tags-geometry.folk claims 54 has canvas projection {{9.47867298578 0 -1} {0 14.38848 (
[ m23358:1058 (s14687:1260) ]
[ m23360:1059 (s14689:1260) ]
[ m23362:1038 (s14691:1260) ]
[ m23364:1040 (s14694:1260) ]
[ m32207:1066 () ]
[ m32431:1039 (s15174:1261) ]
)builtin-programs/tags-geometry.folk claims 54 has canvas projection {{9.47867298578 0 -1} {0 14.3884892086 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 54 has canvas {54 canvas} with width 1024 height 1024 sett (
[ m23353:1039 (s14685:1260) ]
[ m23357:1040 (s14686:1260) ]
[ m23359:1039 (s14688:1260) ]
[ m23361:1040 (s14690:1260) ]
[ m23363:1061 (s14692:1260) ]
[ m32430:1067 (s15172:1263) ]
)builtin-programs/tags-geometry.folk claims 54 has canvas {54 canvas} with width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}
builtin-programs/tags-geometry.folk claims 83 has resolved geometry {tagSize 0.023 left 0.1697 right (
[ m47730:1060 (s64493:1262) ]
[ m47748:1060 (s64514:1262) ]
[ m47780:1063 (s64544:1258) ]
[ m47788:1063 (s64557:1258) ]
[ m31918:1067 () ]
[ m32094:1066 () ]
[ m32253:1067 () ]
[ m32374:1037 (s15113:1266) ]
)builtin-programs/tags-geometry.folk claims 83 has resolved geometry {tagSize 0.023 left 0.1697 right 0.0232 top 0.0246 bottom 0.0921 lineHeight 0.003 advance 0.001758 marginTop 0.01129 marginRight 0.009886 marginBottom 0.007886 marginLeft 0.01 width 0.2159 height 0.1397}
builtin-programs/tags-geometry.folk claims 83 has canvas projection {{9.26354793886 0 -1} {0 14.31639 (
[ m47739:1060 (s64505:1262) ]
[ m47746:1060 (s64512:1262) ]
[ m47754:1064 (s64519:1258) ]
[ m47770:1062 (s64536:1258) ]
)builtin-programs/tags-geometry.folk claims 83 has canvas projection {{9.26354793886 0 -1} {0 14.3163922691 -1} {0 0 1}}
builtin-programs/tags-geometry.folk claims 83 has canvas {83 canvas} with width 1024 height 1024 sett (
[ m47729:1060 (s64499:1262) ]
[ m47735:1064 (s64502:1262) ]
[ m47740:1061 (s64510:1262) ]
[ m47749:1058 (s64518:1262) ]
[ m47764:1057 (s64533:1262) ]
)builtin-programs/tags-geometry.folk claims 83 has canvas {83 canvas} with width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {63 canvas} with width 1024 height (
[ m5178:43 (s12988:51 s12989:51) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {63 canvas} with width 1024 height 1024
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {62 canvas} with width 1024 height (
[ m28091:624 (s55976:745 s55977:745) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {62 canvas} with width 1024 height 1024
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {82 canvas} with width 1024 height (
[ m57069:683 (s38522:827 s38526:827) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {82 canvas} with width 1024 height 1024
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {11 canvas} with width 1024 height (
[ m33894:727 (s14328:865 s14330:865) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {11 canvas} with width 1024 height 1024
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {54 canvas} with width 1024 height (
[ m6546:963 (s53113:1170 s53114:1174) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {54 canvas} with width 1024 height 1024
builtin-programs/tags-geometry.folk wishes the GPU creates canvas {83 canvas} with width 1024 height (
[ m42513:1051 (s60008:1248 s60009:1248) ]
)builtin-programs/tags-geometry.folk wishes the GPU creates canvas {83 canvas} with width 1024 height 1024
builtin-programs/title.folk claims 54-display has a quad (
[ m44346:1038 (s51489:1233 s51497:1233 s51501:1233 s51505:1233) ]
)builtin-programs/title.folk claims 54-display has a quad
builtin-programs/title.folk claims 62 has a quad (
[ m16182:1052 (s40279:1249 s40281:1248 s40283:1247 s40284:1246) ]
)builtin-programs/title.folk claims 62 has a quad
builtin-programs/title.folk claims 63 has a quad (
[ m16428:1053 (s40573:1247 s40575:1244 s40579:1195 s40581:1193) ]
)builtin-programs/title.folk claims 63 has a quad
builtin-programs/title.folk claims 82 has a quad (
[ m17864:1058 (s28216:1253 s28219:1238 s28223:1245 s28227:1245) ]
)builtin-programs/title.folk claims 82 has a quad
builtin-programs/title.folk claims 11 has a quad (
[ m23192:1061 (s14495:1257 s14498:1259 s14501:1258 s14504:1259) ]
)builtin-programs/title.folk claims 11 has a quad
builtin-programs/title.folk claims 54-frame-6 has a quad ()builtin-programs/title.folk claims 54-frame-6 has a quad
builtin-programs/title.folk claims 54 has a quad ()builtin-programs/title.folk claims 54 has a quad
builtin-programs/title.folk claims 54-frame-5 has a quad ()builtin-programs/title.folk claims 54-frame-5 has a quad
builtin-programs/title.folk claims 54-frame-1 has a quad ()builtin-programs/title.folk claims 54-frame-1 has a quad
builtin-programs/title.folk claims 54-frame-4 has a quad ()builtin-programs/title.folk claims 54-frame-4 has a quad
builtin-programs/title.folk claims 54-frame-2 has a quad ()builtin-programs/title.folk claims 54-frame-2 has a quad
builtin-programs/title.folk claims 54-frame-3 has a quad ()builtin-programs/title.folk claims 54-frame-3 has a quad
builtin-programs/title.folk claims 83 has a quad ()builtin-programs/title.folk claims 83 has a quad
builtin-programs/title.folk wishes to draw text onto monitor with position {2896.19187753 1020.395981 (
[ m51774:1064 (s16230:1264) ]
)builtin-programs/title.folk wishes to draw text onto monitor with position {2896.19187753 1020.39598124} scale 36.0 radians -1.56722363723 anchor bottom text {(edited Fri, 08 May 2026, 09:00 PM)}
builtin-programs/calibrate/matlib.folk claims the calibration matrix library is <C:cfile5JsRBY> (
[ m4484:0 (s6282:0) ]
[ m4485:0 (s6285:0 s6288:0 s6291:0 s6292:0 s6293:0) ]
[ m23571:0 (s31217:0) ]
[ m23573:0 (s31220:0) ]
)builtin-programs/calibrate/matlib.folk claims the calibration matrix library is <C:cfile5JsRBY>
builtin-programs/calibrate/refine.folk claims the calibration refiner is {apply \{fn\ envStack\ args\ ()builtin-programs/calibrate/refine.folk claims the calibration refiner is {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {{modelLib matLib setCameraToProjectorExtrinsics
calibrationPoses calibration} \n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/refine.folk 565}} {{this builtin-programs/calibrate/refine.folk} {} {} {configCcWithLibapriltag {apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} {refineLib <C:cfileEn73CX> ^configCcWithLibapriltag {{apply \{fn\ envStack\ args\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lassign\ \$fn\ argNames\ body\ sourceInfo\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ source\ \$body\]\ ne\ \$sourceInfo\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ body\ \[info\ source\ \$body\ \{*\}\$sourceInfo\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ env\ \[dict\ merge\ \{*\}\$envStack\]\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __envStack\ \$envStack\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ env\ __env\ \$env\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ argNames\ \[list\ \{*\}\[dict\ keys\ \$env\]\ \{*\}\$argNames\]\n\ \ \ \ \ \ \ \ \ \ \ \ tailcall\ apply\ \[list\ \$argNames\ \$body\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ values\ \$env\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\$args\n\ \ \ \ \ \ \ \ \} {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}} {{this builtin-programs/apriltags.folk} {} {} {imageLib <C:cfileV8MUaU>} {^configCcWithLibapriltag {cc \n\ \ \ \ \$cc\ cflags\ -I./vendor/apriltag\n\ \ \ \ \$cc\ endcflags\ -Wl,-rpath,\[pwd\]/vendor/apriltag/build\ \\\n\ \ \ \ \ \ \ \ ./vendor/apriltag/build/libapriltag.so\n {builtin-programs/apriltags.folk 43}}}}}} NUM_TAGS_IN_MODEL 20 ^refineCalibration {{modelLib matLib setCameraToProjectorExtrinsics
calibrationPoses calibration} \n\ \ \ \ fn\ setCameraToProjectorExtrinsics\n\ \ \ \ #\ We\ start\ by\ individually\ refining\ the\ mono\ calibration\ of\n\ \ \ \ #\ the\ camera\ and\ the\ mono\ calibration\ of\ the\ projector.\n\n\ \ \ \ #\ Refine\ the\ camera:\n\n\ \ \ \ set\ cameraCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ cameraCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ camera\ intrinsics\]\n\ \ \ \ dict\ set\ cameraCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[\$modelLib\ isPrintedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \{*\}\[lmap\ corner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ list\ \{*\}\$corner\ 0.0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \{*\}\[dict\ get\ \$tag\ p\]\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ camera\ calibration\\n-------\"\n\ \ \ \ set\ cameraCalibration\ \[refineMonoCalibration\ \$cameraCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ camera\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ camera\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$cameraCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ camera\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$cameraCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Refine\ the\ projector:\n\n\ \ \ \ set\ projectorCalibration\ \[dict\ create\]\n\ \ \ \ dict\ set\ projectorCalibration\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ projector\ intrinsics\]\n\ \ \ \ dict\ set\ projectorCalibration\ poses\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \$calibrationPoses\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ extrinsics\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \\\n\ \ \ \ \ \ \{\n\ \ \ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ \ \ set\ points\ \[list\]\n\ \ \ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ modelCorner\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ points\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ dict\ create\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ R\ \[dict\ get\ \$extrinsics\ R\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ t\ \[dict\ get\ \$extrinsics\ t\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ modelPoints\ \$modelPoints\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ points\ \$points\n\ \ \ \ \ \ \}\]\n\ \ \ \ puts\ \".\\nMono\ projector\ calibration\\n-------\"\n\ \ \ \ set\ projectorCalibration\ \[refineMonoCalibration\ \$projectorCalibration\]\n\n\ \ \ \ dict\ set\ calibration\ projector\ rmse\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ rmse\]\n\ \ \ \ dict\ set\ calibration\ projector\ intrinsics\ \\\n\ \ \ \ \ \ \ \ \[dict\ get\ \$projectorCalibration\ intrinsics\]\n\ \ \ \ dict\ set\ calibration\ projector\ extrinsics\ \\\n\ \ \ \ \ \ \ \ \[lmap\ pose\ \[dict\ get\ \$projectorCalibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ create\ R\ \[dict\ get\ \$pose\ R\]\ t\ \[dict\ get\ \$pose\ t\]\n\ \ \ \ \ \ \ \ \}\]\n\n\ \ \ \ #\ Reconstruct\ camera->projector\ extrinsics\ after\ refinement.\n\ \ \ \ setCameraToProjectorExtrinsics\ \$modelLib\ calibration\ \$calibrationPoses\n\n\ \ \ \ #\ Now\ we\ do\ stereo\ refinement\ of\ the\ reprojection\ error\n\ \ \ \ #\ of\ the\ entire\ system,\ including\ all\ intrinsics\ and\n\ \ \ \ #\ extrinsics.\n\n\ \ \ \ #\ Set\ up\ static\ data\ for\ fitting.\n\ \ \ \ set\ poseCount\ 0\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ poseCameraPoints\ \[list\]\n\ \ \ \ set\ poseProjectorPoints\ \[list\]\n\ \ \ \ set\ poseExtrinsics\ \[list\]\;\ #\ used\ later\ to\ only\ keep\ extrinsics\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ for\ poses\ we're\ using\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$calibrationPoses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$calibrationPoses\ \$i\]\n\ \ \ \ \ \ \ \ set\ H_modelToProjector\ \[dict\ get\ \$pose\ H_modelToDisplay\]\n\n\ \ \ \ \ \ \ \ #\ If\ the\ pose\ has\ been\ estimated\ to\ be\ _behind_\ the\ camera\n\ \ \ \ \ \ \ \ #\ or\ projector\ (z\ <\ 0),\ we\ should\ skip\ it.\n\ \ \ \ \ \ \ \ set\ tc\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ set\ tp\ \[dict\ get\ \[lindex\ \[dict\ get\ \$calibration\ projector\ extrinsics\]\ \$i\]\ t\]\n\ \ \ \ \ \ \ \ if\ \{\[lindex\ \$tc\ 2\]\ <\ 0\ ||\ \[lindex\ \$tp\ 2\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \"SKIP\ POSE:\$i\"\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ cameraPoints\ \[list\]\n\ \ \ \ \ \ \ \ set\ projectorPoints\ \[list\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ tag\}\ \[dict\ get\ \$pose\ tags\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ We\ only\ look\ at\ _projected_\ tags\ &\ they\ have\ to\ be\n\ \ \ \ \ \ \ \ \ \ \ \ #\ in\ `tags`,\ so\ were\ actually\ detected\ by\ the\ camera.\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[\$modelLib\ isProjectedTag\ \$id\]\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ j\ 0\}\ \{\$j\ <\ 4\}\ \{incr\ j\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ modelCorner\ \[lindex\ \[dict\ get\ \$pose\ model\ \$id\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ modelPoints\ \[list\ \{*\}\$modelCorner\ 0.0\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cameraPoints\ \[lindex\ \[dict\ get\ \$tag\ p\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ projectorPoints\ \[\$matLib\ applyHomography\ \$H_modelToProjector\ \$modelCorner\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ poseCount\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\$modelPoints\n\ \ \ \ \ \ \ \ lappend\ poseCameraPoints\ \{*\}\$cameraPoints\n\ \ \ \ \ \ \ \ lappend\ poseProjectorPoints\ \{*\}\$projectorPoints\n\ \ \ \ \ \ \ \ lappend\ poseExtrinsics\ \[lindex\ \[dict\ get\ \$calibration\ camera\ extrinsics\]\ \$i\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ stereoSetPoints\ \$poseCount\ \$posePointsCount\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseModelPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseCameraPoints\]\ \\\n\ \ \ \ \ \ \ \ \[concat\ \{*\}\$poseProjectorPoints\]\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\ \ \ \ \$refineLib\ stereoSetIntrinsics\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ camera\ intrinsics\ \$intrName\n\ \ \ \ \}\]\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ projector\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[list\ \{*\}\[rotationMatrixToRotationVector\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ get\ \$calibration\ R_cameraToProjector\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{*\}\[dict\ get\ \$calibration\ t_cameraToProjector\]\]\n\ \ \ \ foreach\ extrinsic\ \$poseExtrinsics\ \{\n\ \ \ \ \ \ \ \ dict\ with\ extrinsic\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \$R\]\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ params\ \{*\}\$t\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ puts\ \".\\nStereo\ refine\ (\$poseCount\ poses):\"\n\ \ \ \ set\ refined\ \[\$refineLib\ stereoRefineCalibrationOptimize\ \$params\]\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ dict\ set\ calibration\ R_cameraToProjector\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ dict\ set\ calibration\ t_cameraToProjector\ \[lrange\ \$refined\ 3\ 5\]\n\n\ \ \ \ #\ TODO:\ Fixup\ the\ extrinsics\ of\ the\ poses.\ They\ don't\ really\n\ \ \ \ #\ matter.\n\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/refine.folk 565}} ^refineMonoCalibration {calibration \n\ \ \ \ #\ Load\ the\ example\ data\ for\ fitting.\n\ \ \ \ set\ poseModelPoints\ \[list\]\n\ \ \ \ set\ posePoints\ \[list\]\n\ \ \ \ set\ posePointsCount\ \[list\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ set\ modelPoints\ \[dict\ get\ \$pose\ modelPoints\]\n\ \ \ \ \ \ \ \ lappend\ poseModelPoints\ \{*\}\[concat\ \{*\}\$modelPoints\]\n\n\ \ \ \ \ \ \ \ set\ points\ \[dict\ get\ \$pose\ points\]\n\ \ \ \ \ \ \ \ lappend\ posePoints\ \{*\}\[concat\ \{*\}\$points\]\n\n\ \ \ \ \ \ \ \ lappend\ posePointsCount\ \[llength\ \$points\]\n\ \ \ \ \}\n\ \ \ \ \$refineLib\ monoSetPoints\ \[llength\ \[dict\ get\ \$calibration\ poses\]\]\ \\\n\ \ \ \ \ \ \ \ \$posePointsCount\ \$poseModelPoints\ \$posePoints\n\n\ \ \ \ set\ intrNames\ \{fx\ cx\ fy\ cy\ k1\ k2\ p1\ p2\}\n\n\ \ \ \ #\ Load\ the\ initial\ guesses\ for\ all\ parameters\ for\ fitting.\n\ \ \ \ set\ params\ \[lmap\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ get\ \$calibration\ intrinsics\ \$intrName\n\ \ \ \ \}\]\n\ \ \ \ foreach\ pose\ \[dict\ get\ \$calibration\ poses\]\ \{\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[rotationMatrixToRotationVector\ \[dict\ get\ \$pose\ R\]\]\n\ \ \ \ \ \ \ \ lappend\ params\ \{*\}\[dict\ get\ \$pose\ t\]\n\ \ \ \ \}\n\n\ \ \ \ #\ Do\ the\ actual\ optimization:\n\ \ \ \ set\ refined\ \[\$refineLib\ monoRefineCalibrationOptimize\ \$params\]\n\n\ \ \ \ #\ Unspool\ the\ optimization\ result\ into\ the\ calibration\ data\n\ \ \ \ #\ structure\ and\ return\ that.\n\n\ \ \ \ set\ refined\ \[lassign\ \$refined\ rmse\ \{*\}\$intrNames\]\n\ \ \ \ dict\ set\ calibration\ rmse\ \$rmse\n\ \ \ \ foreach\ intrName\ \$intrNames\ \{\n\ \ \ \ \ \ \ \ dict\ set\ calibration\ intrinsics\ \$intrName\ \[set\ \$intrName\]\n\ \ \ \ \}\n\ \ \ \ #\ HACK:\ zero\ out\ skew.\n\ \ \ \ dict\ set\ calibration\ intrinsics\ s\ 0.0\n\n\ \ \ \ set\ poses\ \[dict\ get\ \$calibration\ poses\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \[llength\ \$poses\]\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ set\ pose\ \[lindex\ \$poses\ \$i\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ R\ \[rotationVectorToRotationMatrix\ \[lrange\ \$refined\ 0\ 2\]\]\n\ \ \ \ \ \ \ \ dict\ set\ pose\ t\ \[lrange\ \$refined\ 3\ 5\]\n\ \ \ \ \ \ \ \ lset\ poses\ \$i\ \$pose\n\ \ \ \ \ \ \ \ set\ refined\ \[lrange\ \$refined\ 6\ end\]\n\ \ \ \ \}\n\ \ \ \ dict\ set\ calibration\ poses\ \$poses\n\n\ \ \ \ return\ \$calibration\n {builtin-programs/calibrate/refine.folk 509}} ^rotationVectorToRotationMatrix {r \n\ \ \ \ set\ theta\ \[norm\ \$r\]\n\ \ \ \ if\ \{abs(\$theta)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \[mkIdentity\ 3\]\n\ \ \ \ \}\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$theta\]\ \$r\]\n\ \ \ \ set\ ux\ \[list\ \[list\ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 2\]\]\ \[getelem\ \$u\ 1\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[getelem\ \$u\ 2\]\ \ \ \ \ \ \ \ \ \ 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[*\ -1.0\ \[getelem\ \$u\ 0\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \[*\ -1.0\ \[getelem\ \$u\ 1\]\]\ \[getelem\ \$u\ 0\]\ \ \ \ \ \ \ \ \ \ 0\]\]\n\ \ \ \ return\ \[add\ \[scale\ \$(cos(\$theta))\ \[mkIdentity\ 3\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[add\ \[scale\ \[expr\ \{1.0\ -\ cos(\$theta)\}\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[matmul\ \$u\ \[transpose\ \$u\]\]\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[scale\ \$(sin(\$theta))\ \$ux\]\]\]\n {builtin-programs/calibrate/refine.folk 48}} ^rotationMatrixToRotationVector {R \n\ \ \ \ set\ A\ \[scale\ 0.5\ \[sub\ \$R\ \[transpose\ \$R\]\]\]\n\ \ \ \ set\ rho\ \[list\ \[getelem\ \$A\ 2\ 1\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 0\ 2\]\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$A\ 1\ 0\]\]\n\ \ \ \ set\ s\ \[norm\ \$rho\]\n\ \ \ \ set\ c\ \[expr\ \{(\[getelem\ \$R\ 0\ 0\]\ +\ \[getelem\ \$R\ 1\ 1\]\ +\ \[getelem\ \$R\ 2\ 2\]\ -\ 1)\ /\ 2\}\]\n\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ 1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ 1)\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ return\ \{0\ 0\ 0\}\n\ \ \ \ \}\n\ \ \ \ #\ If\ s\ =\ 0\ and\ c\ =\ -1:\n\ \ \ \ if\ \{abs(\$s)\ <\ 0.0001\ &&\ abs(\$c\ -\ (-1))\ <\ 0.0001\}\ \{\n\ \ \ \ \ \ \ \ #\ let\ v\ =\ a\ nonzero\ column\ of\ R\ +\ I\n\ \ \ \ \ \ \ \ set\ v\ \[getcol\ \[add\ \$R\ \[mkIdentity\ 3\]\]\ 0\]\n\ \ \ \ \ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \[norm\ \$v\]\]\ \$v\]\n\ \ \ \ \ \ \ \ set\ r\ \[scale\ 3.14159\ \$u\]\n\ \ \ \ \ \ \ \ if\ \{abs(\[norm\ \$r\]\ -\ 3.14159)\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ ((abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ abs(\[getelem\ \$r\ 1\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 2\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (abs(\[getelem\ \$r\ 0\])\ <\ 0.0001\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \[getelem\ \$r\ 1\]\ <\ 0)\ ||\n\ \ \ \ \ \ \ \ \ \ \ \ \ (\[getelem\ \$r\ 0\]\ <\ 0))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[scale\ -1\ \$r\]\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$r\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ set\ u\ \[scale\ \[/\ 1.0\ \$s\]\ \$rho\]\n\ \ \ \ set\ theta\ \$(atan2(\$s,\ \$c))\n\ \ \ \ return\ \[scale\ \$theta\ \$u\]\n {builtin-programs/calibrate/refine.folk 12}} cc ::<reference.<C______>.00000000000000000006>}}}
builtin-programs/gpu/vma.folk claims the GPU VMA DLL is /tmp/cfilequ8HAs.so (
[ m13900:0 (s18540:0) ]
[ m23441:0 (s30973:0) ]
)builtin-programs/gpu/vma.folk claims the GPU VMA DLL is /tmp/cfilequ8HAs.so
builtin-programs/gpu/textures.folk claims the GPU texture library is <C:cfileHQKyt3> (
[ m18000:0 (s27448:0 s27451:0) ]
[ m18001:0 (s23869:0) ]
[ m20734:0 (s31107:0 s31108:0 s31109:0 s31110:0 s31111:0 s31112:0 s31113:0) ]
[ m23442:0 (s33520:0) ]
)builtin-programs/gpu/textures.folk claims the GPU texture library is <C:cfileHQKyt3>
builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {208} height {208} componen (
[ m18009:0 (s23879:0) ]
)builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c466c40}} as texture 1
builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {192} height {192} componen (
[ m18010:0 (s23876:0) ]
)builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {192} height {192} components {3} bytesPerRow {576} uniq {0} data {(uint8_t*) 0x79d17c42a090}} as texture 2
builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {200} height {200} componen (
[ m18011:0 (s23877:0) ]
)builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {200} height {200} components {3} bytesPerRow {600} uniq {0} data {(uint8_t*) 0x79d17c2f4430}} as texture 3
builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {208} height {208} componen (
[ m18012:0 (s23880:0) ]
)builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {208} height {208} components {3} bytesPerRow {624} uniq {0} data {(uint8_t*) 0x79d17c298ac0}} as texture 4
builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {100} height {100} componen ()builtin-programs/gpu/textures.folk claims the GPU has loaded image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} as texture 18
builtin-programs/gpu/pipelines.folk claims the GPU pipeline library is <C:cfilekUErd7> (
[ m20731:0 (s27450:0) ]
[ m20733:0 (s27906:0) ]
[ m20732:0 (s27449:0) ]
)builtin-programs/gpu/pipelines.folk claims the GPU pipeline library is <C:cfilekUErd7>
builtin-programs/gpu/pipelines.folk claims the GPU pipeline compiler library is <library:/tmp/pipelin (
[ m20735:0 (s30971:0 s30974:0 s30975:0) ]
)builtin-programs/gpu/pipelines.folk claims the GPU pipeline compiler library is <library:/tmp/pipelineCompiler_n0FQo0.tcl>
builtin-programs/gpu/draw.folk claims the GPU draw library is <C:cfile7Rjpvq> (
[ m23440:0 (s30972:0) ]
)builtin-programs/gpu/draw.folk claims the GPU draw library is <C:cfile7Rjpvq>
builtin-programs/gpu/draw.folk claims the GPU compiles function wedge2d to {{vec2 v vec2 w} {} float ()builtin-programs/gpu/draw.folk claims the GPU compiles function wedge2d to {{vec2 v vec2 w} {} float {
return v.x * w.y - v.y * w.x;
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function rotate to {{vec2 v float a} {} vec2 { ()builtin-programs/gpu/draw.folk claims the GPU compiles function rotate to {{vec2 v float a} {} vec2 {
float s = sin(a);
float c = cos(a);
mat2 m = mat2(c, s, -s, c);
return m * v;
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function invBilinear to {{vec2 pos vec2 p2 vec ()builtin-programs/gpu/draw.folk claims the GPU compiles function invBilinear to {{vec2 pos vec2 p2 vec2 p3 vec2 p1 vec2 p0} {wedge2d {{vec2 v vec2 w} {} float {
return v.x * w.y - v.y * w.x;
}}} vec2 {
vec2 q = pos - p0;
vec2 b1 = p1 - p0;
vec2 b2 = p2 - p0;
vec2 b3 = p0 - p1 - p2 + p3;
// Set up quadratic formula
float A = wedge2d(b2, b3);
float B = wedge2d(b3, q) - wedge2d(b1, b2);
float C = wedge2d(b1, q);
// Solve for v
vec2 uv;
if (abs(A) < 0.001) {
// Linear form
uv.y = -C / B;
} else {
// Quadratic form. Take positive root for CCW winding with V-up
float discrim = B * B - 4.0 * A * C;
// Fix from https://www.reedbeta.com/blog/quadrilateral-interpolation-part-2/#comment-3629608573
// (makes images not break with certain vertex inputs)
uv.y = 2.0 * C / (-B - sqrt(discrim));
// uv.y = 0.5 * (-B + sqrt(discrim)) / A;
}
// Solve for u, using largest-magnitude component
vec2 denom = b1 + uv.y * b3;
if (abs(denom.x) > abs(denom.y))
uv.x = (q.x - b2.x * uv.y) / denom.x;
else
uv.x = (q.y - b2.y * uv.y) / denom.y;
uv.y = 1.0 - uv.y;
return uv;
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function bboxBezier to {{vec2 p0 vec2 p1 vec2 ()builtin-programs/gpu/draw.folk claims the GPU compiles function bboxBezier to {{vec2 p0 vec2 p1 vec2 p2 vec2 p3} {} vec4 {
// Exact BBox to a quadratic bezier
// extremes
vec2 mi = min(p0,p3);
vec2 ma = max(p0,p3);
vec2 k0 = -1.0*p0 + 1.0*p1;
vec2 k1 = 1.0*p0 - 2.0*p1 + 1.0*p2;
vec2 k2 = -1.0*p0 + 3.0*p1 - 3.0*p2 + 1.0*p3;
vec2 h = k1*k1 - k0*k2;
if( h.x>0.0 )
{
h.x = sqrt(h.x);
//float t = (-k1.x - h.x)/k2.x;
float t = k0.x/(-k1.x-h.x);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.x + 3.0*s*s*t*p1.x + 3.0*s*t*t*p2.x + t*t*t*p3.x;
mi.x = min(mi.x,q);
ma.x = max(ma.x,q);
}
//t = (-k1.x + h.x)/k2.x;
t = k0.x/(-k1.x+h.x);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.x + 3.0*s*s*t*p1.x + 3.0*s*t*t*p2.x + t*t*t*p3.x;
mi.x = min(mi.x,q);
ma.x = max(ma.x,q);
}
}
if( h.y>0.0)
{
h.y = sqrt(h.y);
//float t = (-k1.y - h.y)/k2.y;
float t = k0.y/(-k1.y-h.y);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.y + 3.0*s*s*t*p1.y + 3.0*s*t*t*p2.y + t*t*t*p3.y;
mi.y = min(mi.y,q);
ma.y = max(ma.y,q);
}
//t = (-k1.y + h.y)/k2.y;
t = k0.y/(-k1.y+h.y);
if( t>0.0 && t<1.0 )
{
float s = 1.0-t;
float q = s*s*s*p0.y + 3.0*s*s*t*p1.y + 3.0*s*t*t*p2.y + t*t*t*p3.y;
mi.y = min(mi.y,q);
ma.y = max(ma.y,q);
}
}
return vec4( mi, ma );
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function sdSegmentSq to {{vec2 p vec2 a vec2 b ()builtin-programs/gpu/draw.folk claims the GPU compiles function sdSegmentSq to {{vec2 p vec2 a vec2 b} {} float {
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
vec2 d = pa - ba*h;
return dot(d, d);
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function udBezier to {{vec2 p0 vec2 p1 vec2 p2 ()builtin-programs/gpu/draw.folk claims the GPU compiles function udBezier to {{vec2 p0 vec2 p1 vec2 p2 vec2 p3 vec2 pos} {} vec2 {
const int kNum = 50;
vec2 res = vec2(1e10,0.0);
vec2 a = p0;
for( int i=1; i<kNum; i++ )
{
float t = float(i)/float(kNum-1);
float s = 1.0-t;
vec2 b = p0*s*s*s + p1*3.0*s*s*t + p2*3.0*s*t*t + p3*t*t*t;
float d = sdSegmentSq( pos, a, b );
if( d<res.x ) res = vec2(d,t);
a = b;
}
return vec2(sqrt(res.x),res.y);
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function glyphMsd to {{sampler2D atlas vec4 at ()builtin-programs/gpu/draw.folk claims the GPU compiles function glyphMsd to {{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));
}}
builtin-programs/gpu/draw.folk claims the GPU compiles function median to {{float r float g float b} ()builtin-programs/gpu/draw.folk claims the GPU compiles function median to {{float r float g float b} {} float {
return max(min(r, g), min(max(r, g), b));
}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline image to {pipeline {(VkPipeline) 0xcc ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline image to {pipeline {(VkPipeline) 0xcc00000000cc} pipelineLayout {(VkPipelineLayout) 0xcb00000000cb} pushConstantsSize {112} encodePushConstants {(PushConstantsEncoder*) 0x79d1c4397a90}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline circle to {pipeline {(VkPipeline) 0xd ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline circle to {pipeline {(VkPipeline) 0xd600000000d6} pipelineLayout {(VkPipelineLayout) 0xd500000000d5} pushConstantsSize {112} encodePushConstants {(PushConstantsEncoder*) 0x79d18c15c5b0}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline fillTriangle to {pipeline {(VkPipelin ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline fillTriangle to {pipeline {(VkPipeline) 0x1010000000101} pipelineLayout {(VkPipelineLayout) 0x1000000000100} pushConstantsSize {96} encodePushConstants {(PushConstantsEncoder*) 0x79d19dac7240}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline apriltag to {pipeline {(VkPipeline) 0 ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline apriltag to {pipeline {(VkPipeline) 0x1040000000104} pipelineLayout {(VkPipelineLayout) 0x1030000000103} pushConstantsSize {128} encodePushConstants {(PushConstantsEncoder*) 0x79d1785e67f0}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline line to {pipeline {(VkPipeline) 0x118 ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline line to {pipeline {(VkPipeline) 0x1180000000118} pipelineLayout {(VkPipelineLayout) 0x1170000000117} pushConstantsSize {112} encodePushConstants {(PushConstantsEncoder*) 0x79d19467a900}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline dashed-line to {pipeline {(VkPipeline ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline dashed-line to {pipeline {(VkPipeline) 0x1200000000120} pipelineLayout {(VkPipelineLayout) 0x11f000000011f} pushConstantsSize {128} encodePushConstants {(PushConstantsEncoder*) 0x79d1b483b230}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline arc to {pipeline {(VkPipeline) 0x16a0 ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline arc to {pipeline {(VkPipeline) 0x16a000000016a} pipelineLayout {(VkPipelineLayout) 0x1690000000169} pushConstantsSize {48} encodePushConstants {(PushConstantsEncoder*) 0x79d18011d140}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline composite-canvas to {pipeline {(VkPip ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline composite-canvas to {pipeline {(VkPipeline) 0x1760000000176} pipelineLayout {(VkPipelineLayout) 0x1750000000175} pushConstantsSize {112} encodePushConstants {(PushConstantsEncoder*) 0x79d1bc9a0470}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline glyph to {pipeline {(VkPipeline) 0x1a ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline glyph to {pipeline {(VkPipeline) 0x1a200000001a2} pipelineLayout {(VkPipelineLayout) 0x1a100000001a1} pushConstantsSize {128} encodePushConstants {(PushConstantsEncoder*) 0x79d1701372b0}}
builtin-programs/gpu/draw.folk claims the GPU compiles pipeline curve to {pipeline {(VkPipeline) 0x1a ()builtin-programs/gpu/draw.folk claims the GPU compiles pipeline curve to {pipeline {(VkPipeline) 0x1a500000001a5} pipelineLayout {(VkPipelineLayout) 0x1a400000001a4} pushConstantsSize {64} encodePushConstants {(PushConstantsEncoder*) 0x79d17c5dcba0}}
builtin-programs/gpu/canvases.folk claims the GPU canvas library is <C:cfile8rArAA> ()builtin-programs/gpu/canvases.folk claims the GPU canvas library is <C:cfile8rArAA>
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {monitor canvas} with width 4096 (
[ m23595:0 (s31257:0 s31258:0 s31259:0) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {monitor canvas} with width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {54-display canvas} with settle (
[ m61823:811 () ]
[ m38730:823 () ]
[ m28708:830 () ]
[ m9758:848 () ]
[ m61030:856 () ]
[ m60263:886 () ]
[ m6677:989 (s53233:1173 s53234:1175) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {54-display canvas} with settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {63 canvas} with width 1024 heig (
[ m39805:402 () ]
[ m60596:856 () ]
[ m17438:341 () ]
[ m13623:903 () ]
[ m25838:914 () ]
[ m44645:1033 (s51845:1230) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {63 canvas} with width 1024 height 1024 settle 3ms texture 15 writableInfo {(GpuCanvas*) 0x79d1b50209c0}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {62 canvas} with width 1024 heig (
[ m28095:627 () ]
[ m47937:643 () ]
[ m22518:780 () ]
[ m16085:833 () ]
[ m3061:1024 (s31845:1203) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {62 canvas} with width 1024 height 1024 settle 3ms texture 9 writableInfo {(GpuCanvas*) 0x79cee2e80150}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {82 canvas} with width 1024 heig (
[ m57098:693 () ]
[ m6399:989 () ]
[ m6672:981 (s53224:1175) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {82 canvas} with width 1024 height 1024 settle 3ms texture 19 writableInfo {(GpuCanvas*) 0x79ce966d03c0}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {11 canvas} with width 1024 heig (
[ m33926:725 () ]
[ m55239:733 () ]
[ m46338:776 () ]
[ m60127:888 () ]
[ m25664:915 (s2798:1088) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {11 canvas} with width 1024 height 1024 settle 3ms texture 7 writableInfo {(GpuCanvas*) 0x79ce97b8de40}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {54 canvas} with width 1024 heig (
[ m6579:989 () ]
[ m10870:1007 () ]
[ m37494:1033 () ]
[ m23352:1062 (s14681:1260) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {54 canvas} with width 1024 height 1024 settle 3ms texture 12 writableInfo {(GpuCanvas*) 0x79cd1a258840}
builtin-programs/gpu/canvases.folk claims the GPU has created canvas {83 canvas} with width 1024 heig (
[ m64900:1057 () ]
[ m65094:1056 () ]
[ m47725:1063 (s64489:1262) ]
)builtin-programs/gpu/canvases.folk claims the GPU has created canvas {83 canvas} with width 1024 height 1024 settle 3ms texture 14 writableInfo {(GpuCanvas*) 0x79cc9161c5b0}
builtin-programs/gpu/canvases.folk claims monitor has canvas {monitor canvas} with width 4096 height (
[ m23600:0 (s31266:0) ]
[ m23602:0 (s31268:0) ]
[ m23604:0 (s31270:0) ]
[ m23606:0 (s31272:0) ]
[ m23651:0 (s31335:0) ]
[ m51780:1064 (s16237:1262) ]
[ m6782:1066 (s38751:1263) ]
[ m32130:1067 () ]
[ m32295:1067 () ]
[ m32300:1062 () ]
[ m32315:1067 () ]
[ m32334:1067 () ]
[ m32351:1067 (s15067:1265) ]
[ m32380:1066 (s15107:1266) ]
[ m32472:1040 (s15213:1266) ]
[ m32474:1040 (s15214:1262) ]
[ m32497:1040 (s15240:1266) ]
[ m32532:1066 (s15278:1264) ]
[ m32563:1067 (s15325:1264) ]
[ m32593:1067 (s15367:1265) ]
)builtin-programs/gpu/canvases.folk claims monitor has canvas {monitor canvas} with width 4096 height 2160 settle 0ms layer 100 texture 6 writableInfo {(GpuCanvas*) 0x79d1741d6260}
builtin-programs/gpu/canvases.folk claims monitor has canvas projection {{0.00048828125 0 -1.0} {0 0. (
[ m23601:0 (s31267:0) ]
[ m23603:0 (s31269:0) ]
[ m23605:0 (s31271:0) ]
[ m23607:0 (s31273:0) ]
[ m51786:1064 (s16240:1262) ]
[ m6786:1066 (s38755:1263 s38756:1263) ]
[ m31813:1067 () ]
[ m31928:1067 () ]
[ m31967:1067 () ]
[ m32021:1067 () ]
[ m32040:1062 () ]
[ m32047:1067 () ]
[ m32121:1067 () ]
[ m32133:1067 () ]
[ m32163:1067 () ]
[ m32184:1067 () ]
[ m32205:1065 () ]
[ m32223:1066 () ]
[ m32271:1065 () ]
[ m32272:1067 () ]
[ m32296:1061 () ]
[ m32302:1064 () ]
[ m32316:1067 () ]
[ m32336:1067 () ]
[ m32353:1067 (s15070:1266) ]
[ m32382:1066 (s15110:1260 s15111:1263) ]
[ m32475:1067 (s15217:1265 s15219:1260) ]
[ m32476:1067 (s15218:1261 s15220:1265) ]
[ m32501:1066 (s15243:1265) ]
[ m32534:1067 (s15281:1265 s15282:1264) ]
[ m32565:1067 (s15329:1264 s15330:1264) ]
[ m32595:1067 (s15372:1266) ]
)builtin-programs/gpu/canvases.folk claims monitor has canvas projection {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}}
builtin-programs/gpu/canvases.folk claims 54-display has canvas {54-display canvas} with settle 0ms w (
[ m6692:989 (s53250:1174) ]
[ m6695:989 (s53252:1172) ]
[ m6698:989 (s53254:1173) ]
[ m6701:989 (s53260:1174) ]
[ m6706:990 (s53265:1175) ]
[ m25712:1065 () ]
[ m25899:1065 () ]
[ m25921:1065 () ]
[ m26112:1067 () ]
[ m26231:1067 () ]
[ m26536:1067 () ]
[ m27084:1067 () ]
[ m30605:1067 () ]
[ m31002:1067 () ]
[ m31401:1067 () ]
[ m31948:1067 () ]
)builtin-programs/gpu/canvases.folk claims 54-display has canvas {54-display canvas} with settle 0ms width 1024 height 1024 texture 10 writableInfo {(GpuCanvas*) 0x79d1742ee150}
builtin-programs/gpu/canvases.folk claims 54-display has canvas projection {{18.9573459716 0 -1} {0 2 (
[ m23421:1040 (s14768:1256) ]
[ m23422:1062 (s14769:1259) ]
[ m23423:1040 (s14771:1222) ]
[ m23424:1062 (s14772:1256) ]
[ m30608:1067 () ]
[ m31004:1067 () ]
[ m31402:1067 () ]
[ m31949:1067 () ]
)builtin-programs/gpu/canvases.folk claims 54-display has canvas projection {{18.9573459716 0 -1} {0 28.7769784173 -1} {0 0 1}}
builtin-programs/gpu/canvases.folk wishes the GPU runs frame prelude handler {apply \{gpuCanvasLib\ g ()builtin-programs/gpu/canvases.folk wishes the GPU runs frame prelude handler {apply \{gpuCanvasLib\ gpuTextureLib\}\ \{\n\ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\ \ \ \ \ \ \ \ upvar\ mostRecentDrawListsByTexture\ mostRecentDrawListsByTexture\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ missingCanvases\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ missingCanvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{!\[info\ exists\ mostRecentDrawListsByTexture\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ mostRecentDrawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ compiles\ pipeline\ /name/\ to\ /pipeline/\]\n\ \ \ \ \ \ \ \ set\ pipelines\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\ dict\ set\ pipelines\ \$name\ \$pipeline\ \}\ \}\n\n\ \ \ \ \ \ \ \ set\ acquiredRefs\ \[list\]\n\n\ \ \ \ \ \ \ \ set\ results\ \[Query!\ the\ GPU\ has\ created\ canvas\ /id/\ with\ /...options/\]\n\ \ \ \ \ \ \ \ set\ canvases\ \[dict\ create\]\n\ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$result\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ with\ options\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ canvases\ \$id\ \$writableInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ \}\n\n\ \ \ \ \ \ \ \ #\ Discard\ cached\ draw-lists\ for\ canvases\ that\n\ \ \ \ \ \ \ \ #\ have\ been\ destroyed,\ since\ we'll\ want\ to\ re-draw\ them\n\ \ \ \ \ \ \ \ #\ if/when\ they\ get\ re-created.\n\ \ \ \ \ \ \ \ foreach\ id\ \[dict\ keys\ \$mostRecentDrawListsByTexture\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$canvases\ \$id\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ mostRecentDrawListsByTexture\ \$id\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ local\ proc\ addToDrawLists\ \{&drawLists\ pipelineName\ options\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ gpuCanvasLib\ gpuCanvasLib\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ pipelines\ pipelines\n\ \ \ \ \ \ \ \ \ \ \ \ upvar\ missingPipelines\ missingPipelines\n\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$pipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{!\[dict\ exists\ \$missingPipelines\ \$pipelineName\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"canvases:\ Missing\ pipeline\ \$pipelineName\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ missingPipelines\ \$pipelineName\ true\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ unset\ missingPipelines\ \$pipelineName\n\ \ \ \ \ \ \ \ \ \ \ \ set\ pipeline\ \[dict\ get\ \$pipelines\ \$pipelineName\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ layer\ \[dict\ getdef\ \$options\ layer\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$options\ instances\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[dict\ get\ \$options\ instances\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ instances\ \[list\ \[dict\ get\ \$options\ arguments\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ instance\ \$instances\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ lappend\ drawLists\ \$layer\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ \$gpuCanvasLib\ draw\ \$pipeline\ \$instance\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ set\ drawListsByTexture\ \[dict\ create\]\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ wi\}\ \$canvases\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsList\ \[Query!\ the\ collected\ results\ for\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[list\ /wisher/\ wishes\ the\ GPU\ draws\ pipeline\ /name/\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ onto\ canvas\ \$id\ with\ /...options/\]\ are\ /results/\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$resultsList\]\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ No\ collect\ statement\ present.\ Just\ reuse\ the\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ last\ draw\ list.\ (Note:\ this\ is\ _not_\ the\ same\ as\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ a\ collect\ statement\ being\ present\ with\ 0\ results\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ inside\ it,\ where\ we\ actually\ shouldn't\ display\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ anything,\ not\ reuse\ the\ last\ draw\ list.)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \[list\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ set\ resultsStmt\ \[lindex\ \$resultsList\ 0\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ ref\ \[dict\ get\ \$resultsStmt\ __ref\]\n\ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ StatementAcquire!\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ acquiredRefs\ \$ref\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ results\ \[dict\ get\ \$resultsStmt\ results\]\n\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Couldn't\ acquire\ the\ collect\ statement\ (it\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ must\ have\ just\ been\ invalidated).\ Just\ reuse\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ the\ last\ one.\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ drawListsByTexture\ \$id\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[dict\ getdef\ \$mostRecentDrawListsByTexture\ \$id\ \[list\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ result\ \$results\ \{\ dict\ with\ result\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ addToDrawLists\ drawListsByTexture(\$id)\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$name\ \$options\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ on\ error\ e\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Error:\ GPU\ draws\ pipeline\ \$name:\ \[errorInfo\ \$e\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ Assert!\ \$this\ claims\ \$wisher\ has\ error\ \$e\ with\ info\ \[errorInfo\ \$e\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ TODO:\ does\ this\ ever\ get\ disposed?\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \}\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ #\ Image\ texture\ wishes\ can\ publish\ draw\ commands\ while\ their\n\ \ \ \ \ \ \ \ #\ descriptor\ writes\ are\ still\ queued.\ Drain\ before\ recording\n\ \ \ \ \ \ \ \ #\ canvas\ command\ buffers\ so\ those\ handles\ are\ drawable.\n\ \ \ \ \ \ \ \ \$gpuTextureLib\ drainDeferredTextureOps\n\n\ \ \ \ \ \ \ \ dict\ for\ \{id\ drawLists\}\ \$drawListsByTexture\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[dict\ exists\ \$mostRecentDrawListsByTexture\ \$id\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (\$drawLists\ eq\ \$mostRecentDrawListsByTexture(\$id))\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ wi\ \[dict\ get\ \$canvases\ \$id\]\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawStart\ \$wi\n\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ layer\ \[lsort\ -real\ \[dict\ keys\ \$drawLists\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ layerDrawList\ \[dict\ get\ \$drawLists\ \$layer\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ drawCommand\ \$layerDrawList\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ try\ \{\ \{*\}\$drawCommand\ \}\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ on\ error\ e\ \{\ puts\ stderr\ \[errorInfo\ \$e\]\ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ \ \ \ \ \$gpuCanvasLib\ drawEnd\n\n\ \ \ \ \ \ \ \ \ \ \ \ dict\ set\ mostRecentDrawListsByTexture\ \$id\ \$drawLists\n\ \ \ \ \ \ \ \ \}\n\n\ \ \ \ \ \ \ \ foreach\ ref\ \$acquiredRefs\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ StatementRelease!\ \$ref\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \} <C:cfile8rArAA> <C:cfileHQKyt3>}
builtin-programs/gpu/canvases.folk wishes the GPU compiles pipeline composite-canvas {
{vec2 (
[ m23526:0 (s36838:0) ]
)builtin-programs/gpu/canvases.folk wishes the GPU compiles pipeline composite-canvas {
{vec2 viewport mat3 surfaceToClip
sampler2D image vec2 a vec2 b vec2 c vec2 d} {
vec2 vertices[6] = vec2[6](a, b, c, a, c, d);
vec3 v = surfaceToClip * vec3(vertices[gl_VertexIndex], 1.0);
return vec4(v.xy/v.z, 0.0, 1.0);
} {fn invBilinear} {
vec2 clipXy = (gl_FragCoord.xy / viewport) * 2.0 - 1.0;
vec3 surfaceXy = inverse(surfaceToClip) * vec3(clipXy, 1.0);
surfaceXy /= surfaceXy.z;
vec2 uv = invBilinear(surfaceXy.xy, a, b, c, d);
if( max( abs(uv.x-0.5), abs(uv.y-0.5))<0.5 ) {
vec4 texColor = texture(image, uv);
// Prevent divide-by-zero errors on empty pixels
if (texColor.a < 0.001) return vec4(0.0);
// Un-premultiply! The compiler's auto-premultiply will cancel this out,
// leaving the canvas pixels mathematically untouched.
return vec4(texColor.rgb / texColor.a, texColor.a);
}
return vec4(0.0);
}}
builtin-programs/gpu/canvases.folk wishes the GPU creates canvas {monitor canvas} with width 4096 hei (
[ m23576:0 (s31228:0 s31229:0) ]
)builtin-programs/gpu/canvases.folk wishes the GPU creates canvas {monitor canvas} with width 4096 height 2160 settle 0ms layer 100
builtin-programs/gpu/canvases.folk wishes the GPU creates canvas {54-display canvas} with settle 0ms (
[ m23669:0 (s31365:0 s31366:0) ]
)builtin-programs/gpu/canvases.folk wishes the GPU creates canvas {54-display canvas} with settle 0ms width 1024 height 1024
builtin-programs/gpu/canvases.folk wishes the GPU draws pipeline composite-canvas with arguments {{40 ()builtin-programs/gpu/canvases.folk wishes the GPU draws pipeline composite-canvas with arguments {{4096 2160} {{0.00048828125 0 -1.0} {0 0.000925925925926 -1.0} {0 0 1}} 6 {0 0} {4096 0} {4096 2160} {0 2160}} layer 100
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m23594:0 (s31255:0) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {monitor canvas} with /...options/} with settle 0ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m23670:0 (s31367:0) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {54-display canvas} with /...options/} with settle 0ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m5185:43 (s12993:51) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {63 canvas} with /...options/} with settle 3ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m28092:625 (s55980:745) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {62 canvas} with /...options/} with settle 3ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m57097:694 (s38539:826) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {82 canvas} with /...options/} with settle 3ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m33925:727 (s14331:857) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {11 canvas} with /...options/} with settle 3ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m6573:964 (s53117:1170) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {54 canvas} with /...options/} with settle 3ms
builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipel (
[ m42528:1051 (s60011:1247) ]
)builtin-programs/gpu/canvases.folk wishes to collect results for {/wisher/ wishes the GPU draws pipeline /name/ onto canvas {83 canvas} with /...options/} with settle 3ms
display monitor has width 4096 height 2160 (
[ m23562:0 (s31204:0) ]
[ m23567:0 (s31211:0) ]
[ m23572:0 (s31218:0) ]
[ m23575:0 (s31222:0 s31224:0) ]
[ m23614:0 (s31282:0) ]
[ m23649:0 (s31333:0) ]
[ m23656:0 (s31344:0) ]
[ m23658:0 (s31347:0) ]
[ m61740:815 () ]
[ m38649:821 () ]
[ m28540:830 () ]
[ m9751:847 () ]
[ m60958:856 () ]
[ m60147:888 () ]
[ m6531:985 (s53053:1174) ]
)display monitor has width 4096 height 2160
builtin-programs/mask-tags.folk wishes to draw a quad onto monitor with p0 {2770.94576434 1140.128944 (
[ m6776:1047 (s38746:1262) ]
)builtin-programs/mask-tags.folk wishes to draw a quad onto monitor with p0 {2770.94576434 1140.12894428} p1 {2769.84476267 1367.39171626} p2 {2530.60087726 1399.3331699} p3 {2539.32201432 1175.33046251} color black layer 100
54 wishes 54-display has a canvas with settle 0ms width 1024 height 1024 (
[ m6676:987 (s31362:0 s53229:1172) ]
)54 wishes 54-display has a canvas with settle 0ms width 1024 height 1024
54 wishes 54-display is outlined white ()54 wishes 54-display is outlined white
54 wishes tag 54 is stabilized ()54 wishes tag 54 is stabilized
54 wishes 54 is outlined green (
[ m6699:990 (s53321:1175) ]
)54 wishes 54 is outlined green
54 wishes 54 is labelled {FPS: 4
Frame count: 6} ()54 wishes 54 is labelled {FPS: 4
Frame count: 6}
54 wishes 54-frame-5 is outlined red ()54 wishes 54-frame-5 is outlined red
54 wishes 54-frame-6 is outlined red ()54 wishes 54-frame-6 is outlined red
54 wishes 54-frame-1 is outlined red ()54 wishes 54-frame-1 is outlined red
54 wishes 54-frame-2 is outlined red ()54 wishes 54-frame-2 is outlined red
54 wishes 54-frame-4 is outlined green ()54 wishes 54-frame-4 is outlined green
54 wishes 54-frame-3 is outlined red ()54 wishes 54-frame-3 is outlined red
54 claims 54-display has resolved geometry {width 0.1055 height 0.0695} (
[ m23420:1040 (s14767:1255) ]
[ m23426:1062 (s14773:1219) ]
[ m23427:1062 (s14774:1223) ]
[ m31611:1058 () ]
[ m31757:1067 () ]
[ m31939:1067 () ]
[ m32076:1064 () ]
[ m32093:1067 () ]
[ m32364:1040 (s15086:1260) ]
[ m32384:1067 () ]
[ m32554:1067 () ]
)54 claims 54-display has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-display has quad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.2397 ()54 claims 54-display has quad {/dev/v4l/by-path/pci-0000:03:00.4-usb-0:4.4:1.0-video-index0 {{-0.239710570951 -0.164275141777 0.626826318506} {-0.229509462209 -0.259301610751 0.582147939229} {-0.168413711799 -0.267798359326 0.614169253153} {-0.178614820549 -0.172771890357 0.658847632446}}}
54 claims 54-frame-1 has resolved geometry {width 0.1055 height 0.0695} (
[ m23414:1062 (s14760:1223) ]
[ m23416:1040 (s14762:1256) ]
[ m25886:1064 () ]
[ m26164:1067 () ]
[ m30510:1067 () ]
[ m31369:1065 () ]
)54 claims 54-frame-1 has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-frame-2 has resolved geometry {width 0.1055 height 0.0695} (
[ m23408:1062 (s14754:1256) ]
[ m23409:1062 (s14755:1257) ]
[ m25490:1065 () ]
[ m26265:1067 () ]
[ m30624:1067 () ]
[ m31029:1067 () ]
[ m31412:1067 () ]
[ m31965:1065 () ]
)54 claims 54-frame-2 has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-frame-3 has resolved geometry {width 0.1055 height 0.0695} (
[ m23402:1062 (s14748:1222) ]
[ m23404:1062 (s14750:1259) ]
[ m31417:1066 () ]
[ m31914:1067 () ]
)54 claims 54-frame-3 has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-frame-4 has resolved geometry {width 0.1055 height 0.0695} (
[ m23397:1062 (s14742:1258) ]
[ m23398:1039 (s14743:1223) ]
[ m30520:1067 () ]
[ m30769:1067 () ]
[ m31387:1066 () ]
[ m31884:1067 () ]
)54 claims 54-frame-4 has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-frame-5 has resolved geometry {width 0.1055 height 0.0695} (
[ m23387:1039 (s14731:1255) ]
[ m23388:1040 (s14732:1260) ]
[ m30496:1066 () ]
[ m31338:1067 () ]
[ m31706:1067 () ]
[ m32186:1067 (s14867:1266) ]
)54 claims 54-frame-5 has resolved geometry {width 0.1055 height 0.0695}
54 claims 54-frame-6 has resolved geometry {width 0.1055 height 0.0695} (
[ m23380:1039 (s14726:1259) ]
[ m23383:1039 (s14727:1256) ]
[ m29107:1067 () ]
[ m29371:1067 () ]
[ m30457:1066 () ]
[ m31681:1066 () ]
[ m32157:1067 () ]
[ m32502:1040 (s15242:1263) ]
)54 claims 54-frame-6 has resolved geometry {width 0.1055 height 0.0695}
builtin-programs/web/textures.folk wishes the web server handles route /textures with handler {applyB (
[ m25262:0 () ]
)builtin-programs/web/textures.folk wishes the web server handles route /textures with handler {applyBlock {
package require base64
set images [$texturesLib copyAllTexturesFromGpu]
html [subst {
<html>
<head>
<title>Textures</title>
<style>
img { max-width: 100%; }
</style>
</head>
<body>
[join [lmap {description imageData} $images {
set b64 [binary encode base64 $imageData]
format {<div><p>%s</p><img src="data:image/png;base64,%s"></div>} $description $b64
}] "\n"]
</body>
</html>
}]
} {{this builtin-programs/web/textures.folk} {} {} {gpuLib <C:cfileog6zwp>} {} {imageLib <C:cfileV8MUaU>} {} {drawLib <C:cfile7Rjpvq>} {} {vmaDll /tmp/cfilequ8HAs.so} {} {gpuTextureLib <C:cfileHQKyt3>} {texturesLib <C:cfile6Gqcwo> cc ::<reference.<C______>.00000000000000000010>}}}
builtin-programs/web/db-lib.folk claims the db library is <C:cfileqnmfGT> (
[ m47677:0 (s60051:0) ]
[ m47692:0 (s60067:0) ]
[ m47698:0 (s60072:0) ]
[ m47710:0 (s60086:0) ]
[ m47716:0 (s60092:0) ]
)builtin-programs/web/db-lib.folk claims the db library is <C:cfileqnmfGT>
builtin-programs/web/report.folk wishes the web server handles route /report with handler {applyBlock (
[ m47678:0 () ]
)builtin-programs/web/report.folk wishes the web server handles route /report with handler {applyBlock {
set aliveCount [$dbLib countAliveStatements $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Report</title>
</head>
<h1>Statement Report</h1>
<div>
<h2>Alive Statements: $aliveCount</h2>
</div>
</html>
}]
} {{this builtin-programs/web/report.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}
builtin-programs/web/atomicallys.folk wishes the web server handles route /atomicallys with handler { (
[ m47694:0 () ]
)builtin-programs/web/atomicallys.folk wishes the web server handles route /atomicallys with handler {applyBlock {
set atomicallys [$dbLib atomicallys $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Atomicallys</title>
</head>
<h1>Atomicallys</h1>
<ol>
[join [lmap atomicallyObj $atomicallys {
lassign $atomicallyObj key latestConvergedNumber versionCount
subst {<li><strong>$key</strong>: latest converged version=$latestConvergedNumber, allVersions length=$versionCount</li>}
}] "\n"]
</ol>
</html>
}]
} {{this builtin-programs/web/atomicallys.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}
builtin-programs/web/statements.folk wishes the web server handles route /statements with handler {ap (
[ m47699:0 () ]
)builtin-programs/web/statements.folk wishes the web server handles route /statements with handler {applyBlock {
set l [list]
# You need to use the Simple form so it doesn't auto-claimize it.
set results [QuerySimple! false /...terms/]
foreach result $results { dict with result {
set childMatchRefs [$dbLib childMatches $db $__ref]
set childMatchInfo [join [lmap childMatchRef $childMatchRefs {
set childStatementRefs [$dbLib childStatements $db $childMatchRef]
subst {
\[ $childMatchRef ($childStatementRefs) \]
}
}] " "]
lappend l [subst {
<li>
<details>
<summary style="[expr {
[lsearch -exact $terms error] != -1
? "color: red"
: ""}]">
$__ref ([$dbLib statementParentCount $db $__ref]): <code>[htmlEscape [string range $terms 0 100]]</code> ($childMatchInfo)</summary>
<pre>[htmlEscape $terms]</pre>
</details>
</li>
}]
} }
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statements</title>
</head>
<h1>Statements</h1>
<ul>[join $l "\n"]</ul>
</html>
}]
} {{this builtin-programs/web/statements.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}
builtin-programs/web/holds.folk wishes the web server handles route /holds with handler {applyBlock { (
[ m47712:0 () ]
)builtin-programs/web/holds.folk wishes the web server handles route /holds with handler {applyBlock {
set holds [$dbLib holds $db]
html [subst {
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Statement Holds</title>
</head>
<h1>Statement Holds</h1>
<ol>
[join [lmap holdObj $holds {
lassign $holdObj key version ref clause
subst {<li>$key ($version): ($ref) <pre>[htmlEscape [string range $clause 0 300]]</pre></li>}
}] "\n"]
</ol>
</html>
}]
} {{this builtin-programs/web/holds.folk} {} {} {dbLib <C:cfileqnmfGT>} {db {(Db*) 0x79d1cc57c010}}}}
builtin-programs/web/dep-graph.folk wishes the web server handles route {/dep-graph\.pdf} with handle (
[ m47717:0 () ]
)builtin-programs/web/dep-graph.folk wishes the web server handles route {/dep-graph\.pdf} with handler {applyBlock \n\ \ \ \ \ \ \ \ set\ dot\ \[apply\ \$dbDotify\ \$dbLib\ \[__db\]\]\n\n\ \ \ \ \ \ \ \ dict\ create\ statusAndHeaders\ \"HTTP/1.1\ 200\ OK\nConnection:\ close\nContent-Type:\ application/pdf\n\n\"\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ body\ \[apply\ \$getDotAsPdf\ \$dot\]\n\ \ \ \ {{this builtin-programs/web/dep-graph.folk} {} {getDotAsPdf {{dot} {
set fd [open |[list dot -Tpdf <<$dot] r]
fconfigure $fd -translation binary
set response [read $fd]
try {
close $fd
return $response
} on error e {
if {[catch {exec which dot}]} {
error "graphviz not installed!"
}
}
}} dbDotify {{dbLib db} {
set dot [list]
set matchRefs [dict create]
foreach stmt [Query! /...anything/] {
set stmtRef [dict get $stmt __ref]
set label [$dbLib clause $db $stmtRef]
set label [join [lmap line [split $label "\n"] {
expr { [string length $line] > 80 ? "[string range $line 0 80]..." : $line }
}] "\n"]
set label [string map {"\"" "\\\""} [string map {"\\" "\\\\"} $label]]
set stmtParentCount [$dbLib statementParentCount $db $stmtRef]
set stmtPtrCount [$dbLib statementPtrCount $db $stmtRef]
lappend dot "<$stmtRef> \[label=\"$stmtRef ($stmtParentCount parents) ($stmtPtrCount ptrs): $label\"\];"
foreach childMatchRef [$dbLib childMatches $db $stmtRef] {
lappend dot "<$stmtRef> -> <$childMatchRef>;"
dict set matchRefs $childMatchRef true
}
}
foreach {matchRef _} $matchRefs {
set match [$dbLib matchAcq $db $matchRef]
if {$match eq "(Match*) 0x0"} { continue }
set matchPtrCount [$dbLib matchPtrCount $db $matchRef]
set matchIsAlive [$dbLib matchIsAlive $db $matchRef]
lappend dot "<$matchRef> \[label=\"$matchRef (alive? $matchIsAlive) ($matchPtrCount)\"\];"
foreach childStatementRef [$dbLib childStatements $db $matchRef] {
lappend dot "<$matchRef> -> <$childStatementRef>;"
}
$dbLib matchRel $db $match
}
return "digraph { rankdir=LR; [join $dot "\n"] }"
}}} {dbLib <C:cfileqnmfGT>} {}}}
builtin-programs/web/nav.folk claims the web navigation HTML is {
<nav>
<a href="/block ()builtin-programs/web/nav.folk claims the web navigation HTML is {
<nav>
<a href="/block-stats">Block stats</a>
<a href="/setup"><button>Setup</button></a>
<a href="/quads">Quads</a>
<a href="/keyboards">Keyboards</a>
<a href="/new"><button>New program</button></a>
<a href="/camera">Camera</a>
<a href="/threads">Threads</a>
<a href="/trie-graph.pdf">Trie graph</a>
<a href="/apriltag-frame">Apriltag frame</a>
<a href="/camera-frame">Camera frame</a>
<a href="/textures">Textures</a>
<a href="/report">Report</a>
<a href="/atomicallys">Atomicallys</a>
<a href="/statements">Statements</a>
<a href="/holds">Holds</a>
<a href="/dep-graph.pdf">Dep graph</a>
</nav>
}
builtin-programs/audio.folk claims the audio library is <C:cfileaDB4QL> (
[ m31822:2 (s1438:3) ]
)builtin-programs/audio.folk claims the audio library is <C:cfileaDB4QL>
builtin-programs/camera/slice.folk wishes 63 has camera slice (
[ m3380:1021 (s32232:1210) ]
)builtin-programs/camera/slice.folk wishes 63 has camera slice
builtin-programs/camera/slice.folk wishes 83 has camera slice (
[ m47753:1064 (s64520:1262) ]
)builtin-programs/camera/slice.folk wishes 83 has camera slice
builtin-programs/decorations/outline.folk wishes to draw a line onto 54 with points {{0 0} {0.211 0} (
[ m23372:1062 (s14705:1259) ]
)builtin-programs/decorations/outline.folk wishes to draw a line onto 54 with points {{0 0} {0.211 0} {0.211 0.139} {0 0.139} {0 0}} width 0.01 color green
builtin-programs/decorations/outline.folk wishes to draw a line onto 83 with points {{0 0} {0.2159 0} (
[ m47755:1060 (s64524:1258) ]
)builtin-programs/decorations/outline.folk wishes to draw a line onto 83 with points {{0 0} {0.2159 0} {0.2159 0.1397} {0 0.1397} {0 0}} width 0.01 color white
builtin-programs/decorations/outline.folk wishes to draw a line onto 82 with points {{0 0} {0.2159 0} (
[ m47738:1064 (s64507:1262) ]
)builtin-programs/decorations/outline.folk wishes to draw a line onto 82 with points {{0 0} {0.2159 0} {0.2159 0.1397} {0 0.1397} {0 0}} width 0.01 color red
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-display with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-display with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color white
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-5 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-5 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color red
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-6 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-6 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color red
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-1 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-1 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color red
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-2 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-2 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color red
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-4 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-4 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color green
builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-3 with points {{0 0} {0 ()builtin-programs/decorations/outline.folk wishes to draw a line onto 54-frame-3 with points {{0 0} {0.1055 0} {0.1055 0.0695} {0 0.0695} {0 0}} width 0.01 color red
62 claims the animation toy's frame count is 6 (
[ m23376:1062 (s14710:1222 s14712:1223 s14713:1259 s14714:1259 s14715:1222 s14716:1223 s14719:1258 s14720:1258 s14721:1259 s14722:1259 s14723:1258 s14724:1259 s14725:1258) ]
[ m31624:1066 () ]
[ m31762:1067 () ]
[ m32098:1067 () ]
[ m32388:1064 () ]
[ m32557:1067 () ]
)62 claims the animation toy's frame count is 6
62 claims the animation toy's fps is 4 (
[ m31219:1067 () ]
[ m31623:1065 () ]
[ m31760:1067 () ]
[ m32095:1067 () ]
[ m32387:1038 () ]
[ m32556:1067 () ]
)62 claims the animation toy's fps is 4
11 wishes 11 displays image https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif (
[ m33945:727 (s14357:865) ]
[ m33950:727 (s14359:846) ]
)11 wishes 11 displays image https://blob.gifcities.org/gifcities/IC6U7E6P23VST5VLFXIQC7O7RLPFVXPX.gif
82 claims tag 82 has geometry {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHe (
[ m6663:984 () ]
)82 claims tag 82 has geometry {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}
82 wishes 83 has contours with threshold 28 epsilon 3.0 minLength 0.01 (
[ m47745:1061 (s64511:1262 s64513:1262) ]
)82 wishes 83 has contours with threshold 28 epsilon 3.0 minLength 0.01
82 wishes 82 is outlined red (
[ m47734:1061 (s64500:1262) ]
)82 wishes 82 is outlined red
builtin-programs/decorations/label.folk wishes to draw text onto 54 with x 0.1055 y 0.0995 scale 0.02 ()builtin-programs/decorations/label.folk wishes to draw text onto 54 with x 0.1055 y 0.0995 scale 0.02 font PTSans-Regular text {FPS: 4
Frame count: 6}
builtin-programs/decorations/label.folk wishes 54 is labelled {FPS: 4
Frame count: 6} with font PTSan ()builtin-programs/decorations/label.folk wishes 54 is labelled {FPS: 4
Frame count: 6} with font PTSans-Regular
builtin-programs/draw/gif.folk wishes 11 displays image {width {100} height {100} components {3} byte ()builtin-programs/draw/gif.folk wishes 11 displays image {width {100} height {100} components {3} bytesPerRow {300} uniq {0} data {(uint8_t*) 0x79d1b034e360}} with scale 1.0
83 claims tag 83 has geometry {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHe (
[ m47711:1064 () ]
)83 claims tag 83 has geometry {tagSize 23mm left 169.7mm right 23.2mm top 24.6mm bottom 92.1mm lineHeight 3mm advance 1.758mm marginTop 11.29mm marginRight 9.886mm marginBottom 7.886mm marginLeft 10mm}
83 claims 83 is a viewport (
[ m47732:1060 (s64494:1262 s64495:1262 s64497:1262) ]
)83 claims 83 is a viewport
83 wishes 83 is outlined white (
[ m47728:1063 (s64491:1262) ]
)83 wishes 83 is outlined white